{"id":51303671,"url":"https://github.com/jingangdidi/chatsong","last_synced_at":"2026-06-30T22:04:51.034Z","repository":{"id":299982056,"uuid":"1004810474","full_name":"jingangdidi/chatsong","owner":"jingangdidi","description":"A lightweight, portable executable for invoking LLM with multi-API support - eliminating installation requirements while maintaining operational efficiency. 轻量级大语言模型api调用工具，无需安装，仅一个~10M可执行文件，支持自定义多种模型（OpenAI、Claude、Gemini、DeepSeek等，以及第三方提供的api）和prompt。","archived":false,"fork":false,"pushed_at":"2026-06-21T12:56:35.000Z","size":42687,"stargazers_count":12,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-21T14:41:18.291Z","etag":null,"topics":["ai-assistant","asr","chatbot","chatgpt-api","deepseek","function-calling","glm","kimi-ai","llm","mcp","minimax","qwen","self-hosted","skills","tts","voice-assistant","voice-cloning","webui"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jingangdidi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-19T08:05:50.000Z","updated_at":"2026-06-21T12:56:39.000Z","dependencies_parsed_at":"2025-06-19T09:26:28.395Z","dependency_job_id":"60646573-60e1-4e0b-a077-219a7159e64e","html_url":"https://github.com/jingangdidi/chatsong","commit_stats":null,"previous_names":["jingangdidi/chatsong"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/jingangdidi/chatsong","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jingangdidi%2Fchatsong","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jingangdidi%2Fchatsong/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jingangdidi%2Fchatsong/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jingangdidi%2Fchatsong/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jingangdidi","download_url":"https://codeload.github.com/jingangdidi/chatsong/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jingangdidi%2Fchatsong/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34984791,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-30T02:00:05.919Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-assistant","asr","chatbot","chatgpt-api","deepseek","function-calling","glm","kimi-ai","llm","mcp","minimax","qwen","self-hosted","skills","tts","voice-assistant","voice-cloning","webui"],"created_at":"2026-06-30T22:04:50.488Z","updated_at":"2026-06-30T22:04:51.024Z","avatar_url":"https://github.com/jingangdidi.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# chatsong\n[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/jingangdidi/chatsong/blob/main/LICENSE)\n\n[中文文档](https://github.com/jingangdidi/chatsong/blob/main/README_zh.md)\n\n**A lightweight(~10M), portable executable for invoking LLM with multi-API support - eliminating installation requirements while maintaining operational efficiency.**\n\n**轻量级大语言模型OpenAI格式api调用工具，无需安装，仅一个~10M可执行文件，支持自定义多种模型（OpenAI、Claude、Gemini、DeepSeek等，以及第三方提供的api）和prompt。**\n\n\u003cimg src=\"https://github.com/jingangdidi/chatsong/raw/main/assets/image/demo.png\"\u003e\n\n## 👑 Features\n- ​💪​ Single-file executable - no installation required\n- 🔐 Privacy first, all data is stored locally\n- 🤖 Unified multi-API support for LLM providers\n- 🎨​ Customize models and prompts within the config file\n- 1️⃣​ Support saving Q\u0026A records as a single HTML file\n- 📚​ Support invoking different models within the same conversation\n- ​🌐​ Support web search and urls\n- ​📤​ Support upload and parse zip, html, pdf, and text file\n- 💻​ Support add local model in config.txt (e.g. provide by llama-server)\n- ✨ Support markdown and code highlight\n- 📊 Support counting the token usage for each conversation and message\n- 💰 Support setting how many contextual messages to include in each query, greatly saving token usage\n- ✂️ Support delete message\n- 😎 Support incognito mode\n- 📡 Support calling APIs compatible with the OpenAI format, such as Deepseek, Qwen, Z.AI GLM, and Moonshot Kimi\n- 🔧 Support built-in filesystem tools\n- 🔨 Support custom external tools and MCP stdio tools\n- 🤔 Support planning mode\n- 🧰 Support skills\n- 👾 Support Discord bot\n- 🎤 Support Qwen3-ASR\n- 📢 Support OmniVoice-TTS\n\n## 🚀 Quick-Start\n**structure**\n```\nsome dir\n├─ chatsong      # single executable file\n├─ config.txt    # config file\n├─ skills        # skills path (optional, `-S`, default: `./skills`)\n├─ Qwen3-ASR     # downloaded Qwen3-ASR model path (optional, `-d`)\n├─ OmniVoice-TTS # downloaded OmniVoice-TTS model path (optional, `-D`)\n└─ chat-log      # save chat log\n```\n**1. download a pre-built binary**\n\n[latest release](https://github.com/jingangdidi/chatsong/releases)\n\n**2. prepare config.txt**\n\nadd your models, api key, endpoint, etc, see [config_template.txt](https://github.com/jingangdidi/chatsong/blob/main/config_template.txt) for details.\n\n**3. start server**\n\nlocal usage:\n```\n./chatsong\n```\nIf you want to start the service on computer A in the intranet and computer B accesses it, computer A needs to specify its own IP address when starting the service, which cannot be the default `127.0.0.1`.\nIt can be specified through the command-line parameter `-a \u003cip\u003e`, for example, the IP of computer A is `192.168.1.5`:\n```\n./chatsong -a 192.168.1.5\n```\nYou can also write it directly in the `config.txt`:\n```\nip_address: \"192.168.1.5\",\n```\n\n**4. visit directly in your browser**\n\n[http://127.0.0.1:8080/v1](http://127.0.0.1:8080/v1)\n\n[http://192.168.1.5:8080/v1](http://192.168.1.5:8080/v1)\n\n**5. terminate the service**\n```\npress `Ctrl+C` to automatically save all chat records to the output directory while simultaneously updating the graph file\n```\n\n## 🎤 ASR + TTS\n\nStarting from v0.5.1, [Qwen3-ASR](https://huggingface.co/Qwen/Qwen3-ASR-0.6B) and [OmniVoice-TTS](https://huggingface.co/k2-fsa/OmniVoice) models are supported. When compiling, `--features asr-cuda,tts-cuda` are specified. When using, `-d` is used to specify the downloaded path of the Qwen3-ASR model, and `-D` is used to specify the downloaded path of the OmniVoice-TTS model. If you want to use voice cloning, `-R` can be used to specify the wav audio file (preferably less than 20 seconds, but not too short). The default voice assistant identity is `daily chat assistant`, and `-E` can be used to change the identity.\n\n## 🧰 skills\nStarting from `v0.4.2`, calling skills is supported. You can place the skill folder directly inside the `skills` folder, or place multiple skill folders within the same subfolder under the `skills` directory; they will be grouped together. You can select them by group using the dropdown on the left side of the page.\n```\nskills\n├─ skill-1\n├─ skill-2\n├─ skill-3\n└─ skill-group-a # This folder can store multiple skills, grouped together\n   ├─ skill-a1\n   ├─ skill-a2\n   └─ skill-a3\n```\n\n## 🛠 Call tools\nStarting from `v0.4.0`, chatsong supports calling tools. In addition to the built-in file system tools, you can also specify your own external tools and MCP's stdio tools through `SingleExternalTool` and `StdIoServer` in `config.txt`.\n\nThe `Call tools` dropdown option on the left side of the page supports the following options:\n\n  - ⚪ white indicates not using any tools\n  - 🔴 red indicates selecting all tools\n  - 🟢 green indicates selecting built-in tools\n  - 🟣 purple indicates selecting all custom external tools\n  - 🟡 yellow indicates selecting MCP tools\n  - other options indicate selecting only one tool\n\nAdd tools in `config.txt`:\n\n**1. built-in tools**\n\n  These tools have been compiled in `chatsong` and do not require additional configuration of `config.txt`. They can be called directly.\n\n**2. custom external tools**\n\n  `command`: fill in the command to be called\n\n  `args`: fill in the script and other parameters\n\n  `description`: fill in the functionality of the tool. The model will use this description to determine whether to use it to complete a task\n\n  `approval`: does calling this tool require user confirmation.\n\n  ```\n  external_tools: [\n    SingleExternalTool(\n      name: \"The name of Tool 1\",\n      command: \"The command called by Tool 1, e.g., ./my_tool.exe\",\n      description: \"The description of Tool 1\",\n      approval: false,\n      schema: r#\"json format schema\"#,\n    ),\n    SingleExternalTool(\n      name: \"The name of Tool 2\",\n      command: \"The command called by Tool 1, e.g., python3\",\n      args: [\"Script and other parameters are specified in this list, e.g., my_tool.py\"],\n      description: \"The description of Tool 2\",\n      approval: true,\n      schema: r#\"json format schema\"#,\n    )\n  ]\n  ```\n\n  Note that the `schema` parameter type and description should be filled in JSON format. As it may contain `\"` and line breaks, it should be placed between `r\"#` and `\"#`. For example, the following example is a Python script I wrote myself to calculate the sum of two numbers. The first parameter is `--a`, which specifies the first number, the second parameter is `--b`, which specifies the second number, the `type`, which specifies the parameter type, and the `description`, which describes the function of the parameter:\n  ```\n  schema: r#\"\n  {\n    \"properties\": {\n      \"a\": {\n        \"type\": \"integer\",\n        \"description\": \"The first value.\",\n      },\n      \"b\": {\n        \"type\": \"integer\",\n        \"description\": \"The second value.\",\n      },\n    },\n    \"required\": [\"a\", \"b\"],\n    \"type\": \"object\",\n  }\n  \"#\n  ```\n\n**3. MCP stdio tools**\n\n  `command`: fill in the command to be called\n\n  `args`: fill in parameters\n\n  ```\n  mcp_servers: [\n    StdIoServer(\n      command: \"./rust-mcp-filesystem\",\n      args: [\n        \"--allow-write\",\n        \"./\",\n      ],\n    ),\n    StdIoServer(\n      command: \"uvx\",\n        args: [\n          \"excel-mcp-server\",\n          \"stdio\",\n        ],\n    ),\n  ]\n  ```\n\nFor complex tasks, you can activate the `plan mode` (only valid when calling tools), which will first create a plan, break down the problem into multiple subtasks, and then complete them one by one. Each step will be judged based on the previously completed steps, whether to proceed to the next step or update the plan. If the task exceeds the capabilities of the model and specified tools, it will end directly and return the reason.\n\n\u003cimg src=\"https://github.com/jingangdidi/chatsong/raw/main/assets/image/plan_mode.png\" width=\"50%\"\u003e\n\n## 🍔 Summarize and compress historical messages\nToo many historical messages can take up valuable context. If previous messages are unrelated to recent tasks, you can use `contextual messages` to limit the number of historical messages included in each question, or click the delete button above the message box to delete them. But if there are many historical messages related to the current tasks, you can click the summary button (\u003cimg src=\"https://github.com/jingangdidi/chatsong/raw/main/assets/image/format-space-less-svgrepo-com.svg\" width=\"18\" height=\"18\" align=\"center\"\u003e) in the bottom left corner of the page to summarize and compress the historical messages within the specified range of `contextual messages`. This not only preserves the previous historical message information, but also reduces the use of context.\n\n## 📺 Detailed Instructions\n[YouTube demo vedio](https://youtu.be/c1DeuIodiSk)\n\n[bilibili demo vedio](https://www.bilibili.com/video/BV1bBuzzAEXs)\n\n[Chinese manual](https://github.com/jingangdidi/chatsong/blob/main/doc/manual_zh.md)\n\n[English manual](https://github.com/jingangdidi/chatsong/blob/main/doc/manual_en.md)\n\n\u003cimg src=\"https://github.com/jingangdidi/chatsong/raw/main/assets/image/screenshot-en-label.png\"\u003e\n\nThis section remains pending completion and will be duly supplemented.\n\n## 🧬 message and Q\u0026A pair\n- One message is a single question or answer.\n- One Q\u0026A pair can contain multiple messages (multiple consecutive questions + multiple consecutive answers)\n\u003cimg src=\"https://github.com/jingangdidi/chatsong/raw/main/assets/image/QA-pair.png\"\u003e\n\n## ⌨️ Building from source\n```\ngit clone https://github.com/jingangdidi/chatsong.git\ncd chatsong\ncargo build --release\n```\nif use `-k` code complation:\n```\ncargo build --release --features code_completion\n```\nif use voice assistant, specify `--features asr-cuda,tts-cuda` during compilation, you can also use CPU inference for ASR and TTS, but it will be slower (`asr,tts`). Mac can use `asr-metal,tts-metal`:\n```\ncargo build --release --features asr-cuda,tts-cuda\n```\n\n## 🚥 Arguments\n```\nUsage: chatsong [-c \u003cconfig\u003e] [-a \u003caddr\u003e] [-p \u003cport\u003e] [-e \u003cengine-key\u003e] [-s \u003csearch-key\u003e] [-C \u003cchannels\u003e] [-w \u003callowed-path\u003e] [-g \u003cgraph\u003e] [-m \u003cmaxage\u003e] [-r] [-l] [-A] [-k] -d \u003casr-dir\u003e -D \u003ctts-dir\u003e [-R \u003cref-audio\u003e] [-E \u003crole\u003e] [-W \u003cwake-words\u003e] [-P \u003cstop-words\u003e] [-S \u003cskills\u003e] [-b \u003cbgc\u003e] [-o \u003coutpath\u003e]\n\nserver for LLM api\n\nOptions:\n  -c, --config        config file, contain api_key, endpoint, model name\n  -a, --addr          ip address, default: 127.0.0.1\n  -p, --port          port, default: 8080\n  -e, --engine-key    search engine key, used for google search\n  -s, --search-key    search api key, used for google search\n  -C, --channels      channel, multiple channels separated by `::`, currently only supports discord: `-C discord:token:guild_id`\n  -w, --allowed-path  allowed path, used for call tools, multiple paths separated by commas, default: ./\n  -g, --graph         graph file, default: search for the latest *.graph file in the output path\n  -m, --maxage        cookie max age, default: 1DAY, support: SECOND, MINUTE, HOUR, DAY, WEEK\n  -r, --share         allow sharing of all chat logs\n  -l, --english       chat page show english\n  -A, --approval-all  approval to call all tools without pop-up prompts\n  -k, --shortcut-key  enable shortcut key code complete, can be used in any editor, support 4 modes: 1. press the Left Ctrl/command 3 times (code completion), 2. press the Right Ctrl/command 3 times (write code), 3. press Left Shift 4 times (debug), 4. press Right Shift 4 times (shell command)\n  -d, --asr-dir       qwen3-ASR model dir (config.json, merges.txt, model.safetensors, tokenizer_config.json, vocab.json)\n  -D, --tts-dir       omni voice TTS model dir (config.json, tokenizer_config.json, model.safetensors, audio_tokenizer/config.json, audio_tokenizer/model.safetensors)\n  -R, --ref-audio     reference audio for omni voice clone\n  -E, --role          prompt role for asr and tts\n  -W, --wake-words    wake words, multiple words separated by commas, default: 你好,hello\n  -P, --stop-words    stop words, multiple words separated by commas, default: 结束,stop\n  -S, --skills        skills path, default: ./skills\n  -b, --bgc           background color, support specify hex color or built-in colors: 1(#E6E6E6), 2(#F5F5DC), 3(#FFFFE0), 4(#E6E6FA), default: 1\n  -o, --outpath       output path, default: ./chat-log\n  -h, --help          display usage information\n```\n\n## 📝 config.txt\n```\n(\n    ip_address: \"127.0.0.1\",       // required, if you want to access from other computers within the intranet, you need to change it to the local IP address, such as 192.168.1.5\n    port: 8080,                    // required\n    google_engine_key: \"\",         // optional, used for web search\n    google_search_key: \"\",         // optional, used for web search\n    allowed_path: \"./\",            // optional, allowed path for tools, multiple paths separated by commas, default: ./\n    maxage: \"1DAY\",                // required, cookie maxage, support: SECOND, MINUTE, HOUR, DAY, WEEK\n    show_english: true,            // required, true: show english page，false: show chinese page\n    skills_path: Some(\"./skills\"), // skills path\n    bgc: \"1\",                      // background color, support hex color (e.g. #F5F5DC, #fff, #000), or built-in color: 1(#E6E6E6), 2(#F5F5DC), 3(#FFFFE0), 4(#E6E6FA), default: 1\n    outpath: \"./chat-log\",         // required, where to save chat log files\n    model_config: [\n        Config(\n            provider: \"openai\",          // required\n            api_key: \"sk-xxx\",           // required\n            endpoint: \"https://api.xxx\", // required\n            models: [\n                Model(\n                    name: \"gpt-4.1-mini-2025-04-14\",          // required\n                    pricing: \"(in: 0.0028/k, out: 0.0112/k)\", // optional\n                    discription: \"OpenAI gpt-4.1 model\",      // optional\n                    group: \"gpt-4.1\",                         // required\n                    is_default: false,                        // required\n                    is_cot: false,                            // required, does it support Chain of thought (CoT) deep reasoning\n                ),\n                Model(\n                    name: \"gpt-4.1-nano-2025-04-14\",\n                    pricing: \"(in: 0.0007/k, out: 0.0028/k)\",\n                    discription: \"OpenAI gpt-4.1 model\",\n                    group: \"gpt-4.1\",\n                    is_default: false,\n                    is_cot: false,\n                ),\n            ],\n        ),\n        Config(\n            provider: \"claude\",\n            api_key: \"sk-xxx\",\n            endpoint: \"https://api.xxx\",\n            models: [\n                Model(\n                    name: \"claude-3-5-sonnet-20241022\",\n                    pricing: \"(in: 0.015/k, out: 0.075/k)\",\n                    discription: \"claude model\",\n                    group: \"Claude\",\n                    is_default: false,\n                    is_cot: false,\n                ),\n                Model(\n                    name: \"claude-3-7-sonnet-20250219\",\n                    pricing: \"(in: 0.015/k, out: 0.075/k)\",\n                    discription: \"claude model\",\n                    group: \"Claude\",\n                    is_default: false,\n                    is_cot: true,\n                ),\n            ],\n        ),\n        Config(\n            provider: \"gemini\",\n            api_key: \"sk-xxx\",\n            endpoint: \"https://api.xxx\",\n            models: [\n                Model(\n                    name: \"gemini-2.0-pro-exp-02-05\",\n                    pricing: \"(in: 0.01/k, out: 0.04/k)\",\n                    discription: \"google gemini model\",\n                    group: \"Gemini\",\n                    is_default: false,\n                    is_cot: false,\n                ),\n                Model(\n                    name: \"gemini-2.0-flash\",\n                    pricing: \"(in: 0.005/k, out: 0.02)\",\n                    discription: \"google gemini model\",\n                    group: \"Gemini\",\n                    is_default: false,\n                    is_cot: false,\n                ),\n            ],\n        ),\n        Config(\n            provider: \"deepseek\",\n            api_key: \"sk-xxx\",\n            endpoint: \"https://api.deepseek.com/v1\",\n            models: [\n                Model(\n                    name: \"deepseek-chat\",\n                    pricing: \"(in: 0.002/k, out: 0.008/k)\",\n                    discription: \"deepseek new model DeepSeek-V3\",\n                    group: \"DeepSeek\",\n                    is_default: true,\n                    is_cot: false,\n                ),\n                Model(\n                    name: \"deepseek-reasoner\",\n                    pricing: \"(in: 0.004/k, out: 0.016/k)\",\n                    discription: \"deepseek new cof model DeepSeek-R1\",\n                    group: \"DeepSeek\",\n                    is_default: false,\n                    is_cot: true,\n                ),\n            ],\n        ),\n    ],\n    prompts: [\n        Prompt(\n            name: \"translator\",\n            content: \"I want you to act as an English translator, spelling corrector and improver. I will speak to you in any language and you will detect the language, translate it and answer in the corrected and improved version of my text, in English. I want you to replace my simplified A0-level words and sentences with more beautiful and elegant, upper level English words and sentences. Keep the meaning same, but make them more literary. I want you to only reply the correction, the improvements and nothing else, do not write explanations.\",\n        ),\n        Prompt(\n            name: \"Rewrite to Rust\",\n            content: \"Rewrite the following code in Rust.\",\n        ),\n    ],\n    external_tools: [\n        SingleExternalTool(\n            name: \"complement_DNA_or_RNA\",\n            command: \"./complement-linux-x86_x64-musl\",\n            description: \"Calculate complement of given DNA or RNA\",\n            approval: false,\n            schema: r#\"\n{\n    \"properties\": {\n        \"seq\": {\n            \"type\": \"string\",\n            \"description\": \"DNA or RNA sequence.\",\n        },\n        \"revcomp\": {\n            \"type\": \"boolean\",\n            \"description\": \"Whether to obtain the reverse complementary sequence. If present, enables reverse complementation.\",\n        },\n        \"rna\": {\n            \"type\": \"boolean\",\n            \"description\": \"Whether to use RNA alphabet.\",\n        },\n    },\n    \"required\": [\"seq\"],\n    \"type\": \"object\",\n}\n\"#,\n        ),\n        SingleExternalTool(\n            name: \"add_two_value\",\n            command: \"python\",\n            args: [\"add_two_value.py\"],\n            description: \"add two value\",\n            approval: false,\n            schema: r#\"\n{\n    \"properties\": {\n        \"a\": {\n            \"type\": \"integer\",\n            \"description\": \"The first value.\",\n        },\n        \"b\": {\n            \"type\": \"integer\",\n            \"description\": \"The second value.\",\n        },\n    },\n    \"required\": [\"a\", \"b\"],\n    \"type\": \"object\",\n}\n\"#,\n        ),\n    ],\n    mcp_servers: [\n        StdIoServer(\n            command: \"./rust-mcp-filesystem\",\n            args: [\n                \"--allow-write\",\n                \"./\",\n            ],\n        ),\n        StdIoServer(\n            command: \"uvx\",\n            args: [\n                \"excel-mcp-server\",\n                \"stdio\",\n            ],\n        ),\n    ]\n)\n```\n\n## ⏰ changelog\n- [2026.05.?] release [v0.5.1](https://github.com/jingangdidi/chatsong/releases/tag/v0.5.1)\n  - 🛠 Fix: Tool calling.\n  - ⭐️ Add: Support `Qwen3-ASR` and `OmniVoice-TTS`, compile `--features asr-cuda,tts-cuda`, the wake-up word is `hello` and the termination word is `stop`.\n- [2026.05.06] release [v0.5.0](https://github.com/jingangdidi/chatsong/releases/tag/v0.5.0)\n  - ⭐️ Add: Support shortcut key code complete, can be used in any editor, support 4 modes: 1. press the Left Ctrl (macos `command`) 3 times (complete the selected code), 2. press the Right Ctrl (macos `command`) 3 times (write code), 3. press the Left Shift 4 times (debug the selected code), 4. press Right Shift 4 times (complete the shell command of the current command line or write a shell command that matches the description of the current command line)\n- [2026.04.29] release [v0.4.2](https://github.com/jingangdidi/chatsong/releases/tag/v0.4.2)\n  - 🛠 Fix: Previously, the system was designed to retry tool calls up to 3 times upon failure, but due to a bug, it would exit immediately instead of retrying. This issue has now been resolved.\n  - ⭐️ Add: Support for skills — specify the path via command-line flag `-S` or via config file named `skills`. Default path is `./skills`. Skills can be placed directly in the `skills` folder, or multiple skill folders can be grouped under subdirectories within `skills`. These groups are selectable via a dropdown on the left sidebar.\n  - ⭐️ Add: Built-in tools now include `codebase`, `web` and `run_x`.\n  - ⭐️ Add: Support for Discord bot integration.\n  - 💪🏻 Optimize: Detailed token statistics are now displayed for each API call, including input tokens (including cached tokens) and output tokens (including reasoning tokens).\n  - 💪🏻 Optimize: Customizable page background color — set via command-line flag `-b` or config file `bgc`. Supports hex colors (e.g., #F5F5DC, #fff, #000) or four built-in options: 1 (#E6E6E6), 2 (#F5F5DC), 3 (#FFFFE0), 4 (#E6E6FA). Default is 1.\n  - 💪🏻 Optimize: Math formulas are now rendered properly in the UI.\n  - 💪🏻 Optimize: Option to disable reasoning (available for deepseek, qwen, kimi, glm).\n  - 💪🏻 Optimize: Separates reasoning content from the final response (supported for deepseek, qwen, kimi, glm, minimax).\n  - 💪🏻 Optimize: When calling the `edit_file` tool, vertical scrollbars are now supported to prevent content overflow beyond the viewport.\n  - 💪🏻 Optimize: Improved rendering of Markdown content on the page.\n- [2026.03.17] release [v0.4.1](https://github.com/jingangdidi/chatsong/releases/tag/v0.4.1)\n  - 🛠Fix: built-in tool `tail_file` and `read_file`.\n  - 🛠Fix: When calling tools, the ID number is always 1.\n  - ⭐️Add: Before calling built-in tools `create_directory`, `edit_file`, `move_file`, `unzip_file`, `write_file`, `zip_directory`, `zip_files`, a pop-up window will appear asking the user to confirm whether to continue.\n  - ⭐️Add: Add `approval` to the custom external tool `SingleExternalTool`.\n  - ⭐️Add: Add `-A`: approval to call all tools without pop-up prompts.\n  - 💪🏻Optimize: Plan mode prompt optimization to make the entire process more robust.\n  - 💪🏻Optimize: Dispaly pretty diffs when calling `edit_file`.\n- [2026.01.01] release [v0.4.0](https://github.com/jingangdidi/chatsong/releases/tag/v0.4.0)\n  - ⭐️Add: Add built-in filesystem tools.\n  - ⭐️Add: Support the use of custom external tools, specified through `SingleExternalTool` in `config.txt`.\n  - ⭐️Add: Support the use of MCP stdio tools, specified through `StdIoServer` in `config.txt`.\n  - ⭐️Add: When calling tools, chatsong supports the planning mode, which first breaks down complex problems into multiple small tasks, and then call tools to implement them one by one.\n  - ⭐️Add: Add a button to summarize the current history (bottom left corner of the page)\n  - ⭐️Add: A custom `top-p` parameter has been added to the back of the left side of the page.\n  - 💪🏻Optimize: Enlarge the question input box.\n  - 💪🏻Optimize: When selecting models and tools from the dropdown menu, use clearer grouping.\n  - 💪🏻Optimize: The token usage is directly obtained from the usage returned by the model, rather than estimated based on tiktoken.\n- [2025.11.06] release [v0.3.3](https://github.com/jingangdidi/chatsong/releases/tag/v0.3.3)\n  - 🛠Fix: When use streaming, if there is no error in obtaining the response but the choices are empty, the answer will not be sent to the client, and a message box for the answer will not be created on the left side of the page. The client messages number will be 1 less than the server, resulting in an error in the next question. Before ending the streaming answer, check if the total string of the answer is empty. If it is empty, send \"no response result\" as the answer.\n  - ⭐️Add: Support Qwen3-vl api, you can send images (png, jpg, jpeg) or PDF documents (automatically converting each page into an image, note that the file extension must be lowercase (.pdf), otherwise only textual content will be extracted) for inquiry. You can use the officially provided Qwen3-VL model or run [llama.cpp](https://github.com/ggml-org/llama.cpp) locally.\n  - 💪🏻Optimize: change command line info `Running on http://127.0.0.1:8080` to `Running on http://127.0.0.1:8080/v1`\n- [2025.10.15] release [v0.3.2](https://github.com/jingangdidi/chatsong/releases/tag/v0.3.2)\n  - 🛠Fix: Fix the issue where other computers on the intranet are not accessible.\n  - 🛠Fix: The abbreviation for the chain of thought model in config.txt is spelled incorrectly, changing \"cof\" to \"cot\".\n  - ⭐️Add: The command line supports \"-h\", previously only \"--help\" could be used.\n  - ⭐️Add: Support calling the official API of the Z.AI GLM model. Currently, the official APIs of Deepseek, QWEN, Z.AI GLM, and Moonshot Kimi can all be called.\n  - 💪🏻Optimize: The default value for \"contextual messages\" on the left side of the page has been changed from \"unlimit\" to \"prompt + 1 Q\u0026A pair\".\n- [2025.08.11] release [v0.3.1](https://github.com/jingangdidi/chatsong/releases/tag/v0.3.1)\n  - 🛠Fix: If the \"stop\" button is clicked while a response is in progress, the next input will be appended to the end of the incomplete answer. Switch \"cancel\" to \"abort\" ensures the server promptly detects the termination signal and ceases responding.\n  - 🛠Fix: When navigating back to the previous chat history page, if any messages have been deleted from the prior records, all subsequent messages following the deleted content will not be displayed due to the discontinuity between server-side IDs and their frontend counterparts.\n- [2025.07.15] release [v0.3.0](https://github.com/jingangdidi/chatsong/releases/tag/v0.3.0)\n  - ⭐️Add: Support delete message.\n  - ⭐️Add: Support incognito mode.\n  - 💪🏻Optimize: Place the upload file button on the left side of the input box.\n  - 💪🏻Optimize: Place the download button and usage button in the bottom left corner of the page.\n- [2025.07.11] release [v0.2.2](https://github.com/jingangdidi/chatsong/releases/tag/v0.2.2)\n  - 🛠Fix: When saving chat history by clicking the left-side button, consecutive unanswered questions at the end should no longer be removed. Previously, this caused ID mismatches between the server and the page when continuing the conversation, resulting in errors.\n  - 🛠Fix: When syncing chat history across different computers, if continuing a conversation on Computer A based on a chat from Computer B, the chat history would fail to save due to path discrepancies upon closing the service.\n  - ⭐️Add: Auto-scroll pauses when scrolling upward and resumes when scrolling downward.\n  - ⭐️Add: Support for line breaks in input questions using Shift + Enter.\n  - ⭐️Add: Display token count for uploaded files. If the file is an image or audio, the token count will not be shown.\n  - 💪🏻Optimize: Command logs now use LocalTime (e.g., 2025-07-07T13:33:48.032687+08:00) instead of the default UTC time.\n  - 💪🏻Optimize: The command line now displays both the current question number and its corresponding QA pair index. Previously, it only showed the question number. \n- [2025.07.07] release [v0.2.1](https://github.com/jingangdidi/chatsong/releases/tag/v0.2.1)\n  -  🛠Fix: When copying a newly posed question or freshly received answer (excluding prior conversation history) by clicking the avatar, the input field not automatically gains focus.\n  -  🛠Fix: Token consumption not updating upon query submission.\n  -  🛠Fix: Lack of response in non-streaming output scenarios.\n  -  ⭐️Add: When using web search, prefix the timestamp of the query with 🌐 to indicate an web search was performed.\n  -  ⭐️Add: Upon hovering over the message box, display the message number, Q\u0026A pair number and token count for this message.\n- [2025.07.01] release [v0.2.0](https://github.com/jingangdidi/chatsong/releases/tag/v0.2.0)\n  - Fix the issue of excessive memory usage by optimizing code highlighting.\n  - Optimize contextual messages, support Q\u0026A pair.\n  - When there is no input question and the last message is an answer, the question will be asked again based on the last question.\n  - There are too many parameters on the left side of the page, so the infrequently used ones will be placed separately on the \"back\". The left parameter area can be flipped by clicking the bottom left button, and the main commonly used parameters will be displayed on the \"front\" by default.\n  - Add a schematic diagram of Q\u0026A pairs by [Excalibraw](https://excalidraw.com)\n- [2025.06.30] release [v0.1.1](https://github.com/jingangdidi/chatsong/releases/tag/v0.1.1)\n- [2025.06.20] release [v0.1.0](https://github.com/jingangdidi/chatsong/releases/tag/v0.1.0)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjingangdidi%2Fchatsong","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjingangdidi%2Fchatsong","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjingangdidi%2Fchatsong/lists"}