Compare commits

...

53 Commits

Author SHA1 Message Date
Arvin Xu 0f04463708 🐛 fix(desktop): persist gateway toggle state across app restarts (#13300)
🐛 fix: persist gateway toggle state across app restarts

The gateway auto-connect logic only checked if the user was logged in,
ignoring whether they had manually disabled the toggle. Added a
`gatewayEnabled` flag to the Electron store that is set on
connect/disconnect and checked before auto-connecting on startup.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 19:31:42 +08:00
Arvin Xu 093fa7bcae feat: support agent tasks system (#13289)
*  feat: agent task system — CLI, review rubrics, workspace, comments, brief tool split

support import md

Major changes:
- Split task CLI into modular files (task/, lifecycle, topic, doc, review, checkpoint, dep)
- Split builtin-tool-task into task + brief tools (conditional injection)
- Task review uses EvalBenchmarkRubric from @lobechat/eval-rubric
- Task workspace: documents auto-pin via Notebook, tree view with folders
- Task comments system (task_comments table)
- Task topics: dedicated TaskTopicModel with userId, handoff fields, review results
- Heartbeat timeout auto-detection in detail API
- Run idempotency (reject duplicate runs) + error rollback
- Topic cancel/delete by topicId only (no taskId needed)
- Integration tests for task router (13 tests)
- interruptOperation fix (string param, not object)
- Global TRPC error handler in CLI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

task document workflow

task handoff loop

🗃️ chore: consolidate task system migrations into single 0095

Merged 7 separate migrations (0095-0101) into one:
- tasks, briefs, task_comments, task_dependencies, task_documents, task_topics tables
- All fields including sort_order, resolved_action/comment, review fields
- Idempotent CREATE TABLE IF NOT EXISTS, DROP/ADD CONSTRAINT, CREATE INDEX IF NOT EXISTS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

fix interruptOperation

topic auto review workflow

topic handoff workflow

finish run topic and brief workflow

support task tool

improve task schema

update

 feat: add onComplete hook to task.run for completion callbacks

When agent execution completes, the hook:
- Updates task heartbeat
- Creates a result Brief (on success) with assistant content summary
- Creates an error Brief (on failure) with error message
- Supports both local (handler) and production (webhook) modes

Uses the new Agent Runtime Hooks system instead of raw stepCallbacks.

LOBE-6160 LOBE-6208

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add Review system — LLM-as-Judge automated review

Task review uses an independent LLM call to evaluate topic output
quality against configurable criteria with pass/fail thresholds.

- TaskReviewService: structured LLM review via generateObject,
  auto-resolves model/provider from user's system agent defaults
- Model: getReviewConfig, updateReviewConfig on TaskModel
- Router: getReview, updateReview, runReview procedures
- CLI: `task review set/view/run` commands
- Auto-creates Brief with review results

LOBE-6165

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add TaskScheduler, multi-topic execution, and handoff context

- TaskScheduler: interface + Local implementation (setTimeout-based),
  following QueueService dual-mode pattern
- Multi-topic execution: `task run --topics N --delay S` runs N topics
  in sequence with optional delay between them
- Handoff context: buildTaskPrompt() queries previous topics by
  metadata.taskId and injects handoff summaries into the next topic's
  prompt (sliding window: latest full, older summaries only)
- Heartbeat auto-update between topics

LOBE-6161

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add Heartbeat watchdog + heartbeat CLI

Watchdog scans running tasks with expired heartbeats, marks them as
failed, and creates urgent error Briefs. Heartbeat CLI allows manual
heartbeat reporting for testing.

- Model: refactored to use Drizzle operators (isNull, isNotNull, ne)
  instead of raw SQL where possible; fixed findStuckTasks to skip
  tasks without heartbeat data
- Router: heartbeat (manual report), watchdog (scan + fail + brief)
- Router: updateSchema now includes heartbeatInterval, heartbeatTimeout
- CLI: `task heartbeat <id>`, `task watchdog`, `task edit` with
  --heartbeat-timeout, --heartbeat-interval, --description

LOBE-6161

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

♻️ refactor: move CheckpointConfig to @lobechat/types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add task run — trigger agent execution for tasks

Task.run creates a topic, triggers AiAgentService.execAgent with task
context, and streams results via SSE. Supports both agentId and slug.

- Service: added taskId to ExecAgentParams, included in topic metadata
- Router: task.run procedure — resolves agent, builds prompt, calls execAgent,
  updates topic count and heartbeat
- CLI: `task run <id>` command with SSE streaming, --prompt, --verbose

LOBE-6160

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add Checkpoint system for task review gates

Checkpoint allows configuring pause points in task execution flow.
Supports beforeIds (pause before subtask starts) and afterIds (pause
after subtask completes) on parent tasks.

- Model: CheckpointConfig type, getCheckpointConfig, updateCheckpointConfig,
  shouldPauseBeforeStart, shouldPauseAfterComplete
- Router: getCheckpoint, updateCheckpoint procedures; integrated with
  updateStatus for automatic checkpoint triggering
- CLI: `task checkpoint view/set` commands with --before, --after,
  --topic-before, --topic-after, --on-agent-request options
- Tests: 3 new checkpoint tests (37 total)

LOBE-6162

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add dependency unlocking on task completion

When a task completes, automatically check and unlock blocked tasks
whose dependencies are all satisfied (backlog → running). Also notify
when all subtasks of a parent are completed.

- Model: getUnlockedTasks, areAllSubtasksCompleted (Drizzle, no raw SQL)
- Router: updateStatus hook triggers unlocking on completion
- CLI: shows unlocked tasks and parent completion notification
- Tests: 3 new tests (34 total)

LOBE-6164

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add Brief system — schema, model, router, CLI

Brief is a universal Agent-to-User reporting mechanism, not limited to
Tasks. CronJobs, Agents, and future systems can all produce Briefs.

- Schema: briefs table with polymorphic source (taskId, cronJobId, agentId)
- Model: BriefModel with CRUD, listUnresolved (Daily Brief), markRead, resolve
- Router: TRPC brief router with taskId identifier resolution
- CLI: `lh brief` command (list/view/read/resolve)
- Tests: 11 model tests
- Migration: 0096_add_briefs_table.sql

LOBE-6163

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

 feat: add Task system — schema, model, router, CLI

Implement the foundational Task system for managing long-running,
multi-topic agent tasks with subtask trees and dependency chains.

- Schema: tasks, task_dependencies, task_documents tables
- Model: TaskModel with CRUD, tree queries, heartbeat, dependencies, document pinning
- Router: TRPC task router with identifier/id resolution
- CLI: `lh task` command (list/view/create/edit/delete/start/pause/resume/complete/cancel/tree/dep)
- Tests: 31 model tests
- Migration: 0095_add_task_tables.sql

LOBE-6036 LOBE-6054

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* update

* 🐛 fix: update brief model import path and add raw-md vitest plugin

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: eslint import sort in vitest config

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: brief ID validation, auto-review retry, and continueTopicId operationId

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: task integration tests — create test agent for FK, fix children spread

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: task integration tests — correct identifier prefix and agent ID

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: remove unused toolsActivatorRuntime import

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: create real topic in task integration tests to satisfy FK constraint

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: type errors in task prompt tests, handoff schema, and activity mapping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: create real agent/topic/brief records in database model tests for FK constraints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:43:51 +08:00
lobehubbot aa48b856fb Merge remote-tracking branch 'origin/main' into canary 2026-03-26 09:05:30 +00:00
YuTengjing b4d27c7232 🗃️ db: add notification tables (#13295)
🗃️ db: add notification tables migration (UUID, with indexes)
2026-03-26 17:04:47 +08:00
Rdmclin2 dd192eda3e feat: bot support custom markdown render and context injection (#13294)
* feat: support  bot mardown format

* feat: support custom markdownRender and bot context inject

* feat: support custom PORT

* feat: telegram support html render

* feat: slack support markdown render

* chore: feishu and lark don't handle markdown for now
2026-03-26 16:52:35 +08:00
huangkairan c6b0f868ef 🐛 fix: skill page redirect & activeTab handling in Details component (#13255) 2026-03-26 15:39:43 +08:00
Arvin Xu 3bea920193 🔁 chore: sync main branch to canary (#13286)
## Summary
- Sync main branch (v2.1.44 + v2.1.45 releases, agent task system DB
schema) into canary
- Resolved Body.tsx merge conflict by keeping canary version
2026-03-26 15:03:02 +08:00
arvinxx ca16a40a44 Merge remote-tracking branch 'origin/main' into sync/main-to-canary-20260326-v2
# Conflicts:
#	src/routes/(main)/agent/channel/detail/Body.tsx
2026-03-26 15:01:04 +08:00
lobehubbot 59e19310fe 🔖 chore(release): release version v2.1.45 [skip ci] 2026-03-26 05:58:23 +00:00
Arvin Xu b005a9c73b 👷 build: add agent task system database schema (#13280)
* 🗃️ chore: add agent task system database schema

Add 6 new tables for the Agent Task System:
- tasks: core task with tree structure, heartbeat, scheduling
- task_dependencies: inter-task dependency graph (blocks/relates)
- task_documents: MVP workspace document pinning
- task_topics: topic tracking with handoff (jsonb) and review results
- task_comments: user/agent comments with author tracking (text id: cmt_)
- briefs: unresolved notification system (text id: brf_)

All sub-tables include userId FK for row-level user isolation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add self-referential FK on tasks.parentTaskId (ON DELETE SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: use foreignKey() for self-referential parentTaskId to avoid TS circular inference

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add FK on task_topics.topic_id → topics.id (ON DELETE SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: resolve pre-existing TS type-check errors

- Fix i18next defaultValue type (string | null → string)
- Fix i18next options type mismatches
- Fix fieldTags.webhook possibly undefined

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add FK on tasks.currentTopicId → topics.id (ON DELETE SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add FK constraints for assignee, author, topic, and parent fields

- tasks.assigneeUserId → users.id (ON DELETE SET NULL)
- tasks.assigneeAgentId → agents.id (ON DELETE SET NULL)
- tasks.parentTaskId → tasks.id (ON DELETE SET NULL)
- tasks.currentTopicId → topics.id (ON DELETE SET NULL)
- task_comments.authorUserId → users.id (ON DELETE SET NULL)
- task_comments.authorAgentId → agents.id (ON DELETE SET NULL)
- task_topics.topicId → topics.id (ON DELETE SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: change task_topics.topicId FK to ON DELETE CASCADE

Topic deleted → task_topic mapping row removed (not just nulled).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ♻️ refactor: use inline .references() for currentTopicId FK

No circular inference issue — only parentTaskId (self-ref) needs foreignKey().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add FK on task_comments.briefId and topicId (ON DELETE SET NULL)

- task_comments.briefId → briefs.id (SET NULL)
- task_comments.topicId → topics.id (SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ♻️ refactor: merge briefs table into task.ts to fix circular dependency

brief.ts imported task.ts (briefs.taskId FK) and task.ts imported
brief.ts (taskComments.briefId FK), causing circular dependency error.
Merged briefs into task.ts since briefs are part of the task system.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🗃️ chore: add FK on tasks.createdByAgentId → agents.id (ON DELETE SET NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:56:01 +08:00
Rdmclin2 2c657670fe 🐛 fix: skill import url and github address problem (#13261)
* chore: optimize github import placeholder and hint

* fix: support import a github hosted skill.md url

* fix:  reimport skill problem

* fix: github zip url file correctly resovled

* fix:  empty content

* fix: test case

* fix: regex lint
2026-03-26 11:28:31 +08:00
Rylan Cai 4dd271c968 feat(cli): support api key auth in cli (#13190)
*  support cli api key auth

* 🔒 reject invalid x-api-key without fallback auth

* ♻️ clean up cli api key auth diff

* ♻️ clean up cli auth command diff

* ♻️ clean up remaining cli auth diff

* ♻️ split stored auth token fields

* ♻️ trim connect auth surface

* ♻️ drop redundant jwt user id carry-over

* ♻️ trim auth test wording diff

* 🐛 fix api key model imports

* 🐛 fix api key util subpath import

* 🔐 chore(cli): use env-only api key auth

* ♻️ refactor(cli): simplify auth credential flow

*  feat: simplify cli api key login flow

* 🐛 fix(cli): prefer jwt for webapi auth

* ♻️ refactor(cli): trim auth http diff

* 🐛 fix(cli): skip api key auth expiry handling

* 🐛 fix(cli): restore non-jwt expiry handling

* ♻️ refactor(cli): trim connect auth expired diff

* ♻️ refactor(cli): trim login comment diff

* ♻️ refactor(cli): trim resolve token comment diff

* ♻️ refactor(cli): restore connect expiry flow

* ♻️ refactor(cli): trim login api key message

* 🐛 fix(cli): support api key gateway auth

* ♻️ refactor(cli): restore resolve token comment

* ♻️ refactor(cli): trim test-only auth diffs

* ♻️ refactor(cli): restore resolve token comments

*  test(cli): add api key expiry coverage

* 🐛 fix cli auth server resolution and gateway auth

* ♻️ prune auth fix diff noise

* ♻️ unify cli server url precedence

* ♻️ simplify device gateway auth tests

*  add gateway auth edge case coverage

*  remove low-value gateway auth test

* 🐛 fix api key context test mock typing
2026-03-26 10:11:38 +08:00
Arvin Xu b76db6bcbd 🐛 fix(memory): respect agent-level memory toggle when injecting memories (#13265)
* 🐛 fix(memory): respect agent-level memory toggle when injecting memories

When the user disables the memory toggle in ChatInput (which writes to
agent-level chatConfig.memory.enabled), the actual message-sending path
in chat/index.ts was only checking the user-level memoryEnabled setting,
completely ignoring the agent-level override.

This aligns the injection logic with useMemoryEnabled hook:
agent-level config takes priority, falls back to user-level setting.

Also fix pre-commit hook to use bunx instead of npx to ensure the
correct ESLint version (v10) is used in monorepo context.

Adds regression tests verifying all three priority scenarios.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update pre-commit

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 01:51:56 +08:00
Innei 84674b1e10 feat(builtin-tool-local-system): skip intervention for safe paths like /tmp (#13232)
*  feat(builtin-tool-local-system): skip intervention for safe paths like /tmp

Add SAFE_PATH_PREFIXES whitelist to bypass user confirmation for
file operations targeting ephemeral directories (/tmp, /var/tmp).

* Fix intervention audit tests

* Move fs checks into Electron
2026-03-26 01:38:36 +08:00
LobeHub Bot 1cb13d9f93 test: add unit tests for mcpStore selectors (#13240)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 01:19:27 +08:00
Arvin Xu 169f11b63b feat(desktop): add device gateway status indicator in titlebar (#13260)
* support desktop gateway

* support device mode

*  feat(desktop): add device gateway status indicator in titlebar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

*  test(desktop): update getDeviceInfo test to include name and description fields

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ✏️ chore(i18n): update gateway status copy to reference Gateway instead of cloud

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ✏️ chore(i18n): translate Gateway to 网关 in zh-CN

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ✏️ chore(i18n): simplify description placeholder to Optional

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ✏️ chore(desktop): use fixed title 'Connect to Gateway' in device popover

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 01:14:08 +08:00
Arvin Xu 2c7a3f934d 🐛 fix: use display messages for token counting in group chats (#13247)
* 🐛 fix: use partial-json fallback in ToolArgumentsRepairer to recover incomplete args

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: use display messages for token counting in group chats

The TokenTag component used dbMessageSelectors.activeDbMessages which
generates a key without groupId, causing empty results in group chats.
This made the Context Details token tag invisible for group agents.

Switch to using the messageString prop (from mainAIChatsMessageString)
which correctly includes groupId in its key generation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 00:59:45 +08:00
YuTengjing a1e91ab30d test: add tests for topic updatedTime grouping (#13249) 2026-03-25 19:46:40 +08:00
Rdmclin2 4a7c89ec25 fix: discord not create thread & wechat media and connect optimize (#13228)
* fix: avoid subscribe whole channel

* chore: add start message whatever

* chore: remove typing interval

* feat: support typing keep alive

* fix: wechat redis client

* feat: add common gateway

* chore: use persistent to replace websocket

* chore: add wechat tip

* fix: add queue Handoff Succeeded stop typing

* feat: optimize connect status display and wechat connect infomation

* chore: wechat maximum 2048

* feat: support wechat files type

* feat: support wechat image upload

* feat: support wechat image resolve

* fix: lint error

* fix: lint error

* fix: postProcessUrl test case

* chore: moke file service

* chore: add page test case timeout
2026-03-25 18:43:45 +08:00
Neko 684a186e3b 🐛 fix(agent-runtime): missing agentId in context (#13250)
Authored-by-agent: Codex <267193182+codex@users.noreply.github.com>
2026-03-25 18:41:14 +08:00
Rdmclin2 e8a948cfaf style: replace plugin icon with skill icon (#13252)
chore: replace plugin icon  with skill icon
2026-03-25 18:21:36 +08:00
YuTengjing 11daf645e9 💄 style: unlock downgrade restrictions i18n and copy improvements (#13241)
* 💬 chore: add i18n keys for unlocking downgrade restrictions

Add subscription i18n keys:
- plans.downgradeWillCancel: warning shown when action cancels pending downgrade
- plans.pendingDowngrade: button text for pending downgrade target
- Update plans.downgradeTip to reflect cancellation context

LOBE-6155

* 🐛 fix: close model switch panel on clicking multi-provider item in generation mode

* 🌐 i18n: add cancel downgrade schedule translations

* 💄 style: simplify menu and tab labels for billing, credits, and usage

* 💄 style: rename switch success to downgrade and update copy

* 🌐 i18n: add switchDowngradeTarget translation key

* 🌐 i18n: sync translations for downgrade schedule keys
2026-03-25 16:44:49 +08:00
Rdmclin2 a4a03eadc4 chore: remove like github star footer (#13246) 2026-03-25 16:29:04 +08:00
Innei 04ddb992d1 🐛 fix(desktop): add missing Stats and Creds tabs to Electron componentMap (#13243) 2026-03-25 16:27:37 +08:00
LobeHub Bot 991de25b97 🌐 chore: translate non-English comments to English in packages/openapi (#13184)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 15:42:28 +08:00
Arvin Xu 056f390abc 🐛 fix: use partial-json fallback in ToolArgumentsRepairer to recover incomplete args (#13239)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 13:50:34 +08:00
Rdmclin2 9b9949befa chore: remove runtime config in agent builder and doc writer (#13238) 2026-03-25 12:54:35 +08:00
LobeHub Bot 366b02bb46 test: add unit tests for topicReference serverRuntime (#13055)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 12:31:45 +08:00
Hardy ad2087cf65 feat: add Coding Plan providers support (#13203)
*  feat: add Aliyun Bailian Coding Plan provider

- Add new AI provider for Bailian Coding Plan (coding.dashscope.aliyuncs.com/v1)
- Support 8 coding-optimized models: Qwen3.5 Plus, Qwen3 Coder Plus/Next, Qwen3 Max, GLM-5/4.7, Kimi K2.5, MiniMax M2.5
- Reuse QwenAIStream for stream processing
- Static model list (Coding Plan does not support API model fetching)
- Add i18n translations for provider description

*  feat: add MiniMax Coding Plan provider

- Add new AI provider for MiniMax Token Plan (api.minimax.io/v1)
- Support 6 models: MiniMax-M2.7, M2.7-highspeed, M2.5, M2.5-highspeed, M2.1, M2
- Static model list (Coding Plan does not support API model fetching)
- Add i18n translations for provider description

*  feat: add GLM Coding Plan provider

- Add new AI provider for GLM Coding Plan (api.z.ai/api/paas/v4)
- Support 6 models: GLM-5, GLM-5-Turbo, GLM-4.7, GLM-4.6, GLM-4.5, GLM-4.5-Air
- Static model list (Coding Plan does not support API model fetching)
- Add i18n translations for provider description

*  feat: add Kimi Code Plan provider

- Add new AI provider for Kimi Code Plan (api.moonshot.ai/v1)
- Support 3 models: Kimi K2.5, Kimi K2, Kimi K2 Thinking
- Static model list (Coding Plan does not support API model fetching)
- Add i18n translations for provider description

*  feat: add Volcengine Coding Plan provider

- Add new AI provider for Volcengine Coding Plan (ark.cn-beijing.volces.com/api/coding/v3)
- Support 5 models: Doubao-Seed-Code, Doubao-Seed-Code-2.0, GLM-4.7, DeepSeek-V3.2, Kimi-K2.5
- Static model list (Coding Plan does not support API model fetching)
- Add i18n translations for provider description

*  feat: update coding plan providers default enabled models and configurations

*  feat: add reasoningBudgetToken32k and reasoningBudgetToken80k slider variants

- Add ReasoningTokenSlider32k component (max 32*1024)
- Add ReasoningTokenSlider80k component (max 80*1024)
- Add reasoningBudgetToken32k and reasoningBudgetToken80k to ExtendParamsType
- Update ControlsForm to render appropriate slider based on extendParams
- Update ExtendParamsSelect with new options and previews
- Fix ReasoningTokenSlider max value to use 64*Kibi (65536) instead of 64000

* 🔧 fix: support reasoningBudgetToken32k/80k in ControlsForm and modelParamsResolver

- Add reasoningBudgetToken32k and reasoningBudgetToken80k fields to chatConfig type and schema
- Update ControlsForm to use correct name matching for 32k/80k sliders
- Add processing logic for 32k/80k params in modelParamsResolver
- Add i18n translations for extendParams hints

* 🎨 style: use linear marks for reasoning token sliders (32k/80k)

- Switch from log2 scale to linear scale for equal mark spacing
- Add minWidth/maxWidth constraints to limit slider length
- Fix 64k and 80k marks being too close together

* 🎨 fix: use equal-spaced index for reasoning token sliders (32k/80k)

- Slider uses index [0,1,2,3,...] for equal mark spacing
- Map index to token values via MARK_TOKENS array
- Add minWidth/maxWidth to limit slider length when marks increase

*  feat: add reasoningBudgetToken32k for GLM-5 and GLM-4.7 in Bailian Coding Plan

* 🔧 fix: update coding plan API endpoints and model configurations

- minimaxCodingPlan: change API URL to api.minimaxi.com (China site)
- kimiCodingPlan: change API URL to api.kimi.com/coding/v1
- volcengineCodingPlan: update doubao-seed models with correct deploymentName, pricing
- volcengineCodingPlan: add minimax-m2.5 model
- bailianCodingPlan & volcengineCodingPlan: remove unsupported extendParams from minimax-m2.5

*  feat: add Coding Plan tag to provider cards with i18n support

* ♻️ refactor: set showModelFetcher to false for Bailian Coding Plan

- Coding Plan does not support fetching model list via API
- Set both modelList.showModelFetcher and settings.showModelFetcher to false

* 🔧 fix: correct Coding Plan exports case in package.json

*  feat: update coding plan models with releasedAt and remove pricing

* 🔧 fix: remove unsupported reasoning abilities from MiniMax Coding Plan models

* 🐛 fix(modelParamsResolver): fix reasoningBudgetToken32k/80k not being read when enableReasoning is present

- Add nested logic to check which budget field (32k/80k/generic) the model supports when enableReasoning is true
- Move reasoningBudgetToken32k/80k else-if branches before reasoningBudgetToken to ensure correct field is read
- Fix GLM-5/GLM-4.7 models sending wrong budget_tokens value to API
2026-03-25 11:53:16 +08:00
LobeHub Bot 0689dd68a3 🌐 chore: translate non-English comments to English in routes and layout (#13210)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 11:52:28 +08:00
LobeHub Bot 75ea33153f 🌐 chore: translate non-English comments to English in packages/agent-runtime (#13236)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 11:51:28 +08:00
YuTengjing dbff1e0668 🐛 fix: default topic display mode to byUpdatedTime and fix nanoBanana2 resolution enum (#13235) 2026-03-25 11:17:41 +08:00
LobeHub Bot afefe217db test: add unit tests for eval-dataset-parser (#13197)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 10:55:58 +08:00
Arvin Xu fed8b39957 feat: desktop support connect to gateway (#13234)
* support desktop gateway

* support device mode

* support desktop

* fix tests

* improve

* fix tests

* fix tests

* fix case
2026-03-25 10:43:15 +08:00
Rdmclin2 f853537695 Add /new and /stop slash commands for bot message management (#13194)
*  feat(bot): implement /new and /stop slash commands

Add Chat SDK slash command handlers for bot integrations:
- /new: resets conversation state so the next message starts a fresh topic
- /stop: cancels any active agent execution on the current thread

https://claude.ai/code/session_01MDofskrz64tRjh2T6xzGBL

* feat: support telegram text type  commands

* fix: stop commands

* feat: register discord slash commands

* feat: add chat adapter patch

* feat: add interuption action

* chore: add agent thread interuption signal

* chore: optimize interruption result

* fix: /stop command message edit

* chore: create a message when interrupted

* chore: add bot test case

* chore: fix test case

* chore: fix test case and remove duplicate completion

* fix: lint error

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-25 00:31:01 +08:00
Baki Burak Öğün 0cdaf117cb 🌐 fix(locale): translate missing Turkish (tr-TR) strings (#13196)
fix(locale): translate missing Turkish (tr-TR) strings in setting.json

- Translate agentCronJobs.clearTopics, clearTopicsFailed, confirmClearTopics
- Translate agentCronJobs.confirmDeleteCronJob, deleteCronJob, deleteFailed

Co-authored-by: bakiburakogun <bakiburakogun@users.noreply.github.com>
2026-03-25 00:11:55 +08:00
Innei ada555789d 🐛 fix(editor): reset editor state when switching to empty page (#13229)
Fixes LOBE-6321
2026-03-24 21:37:08 +08:00
Arvin Xu 007d2dc554 🐛 fix: compress uploaded images to max 1920px before sending to API (#13224)
* 🐛 fix: compress uploaded images to max 1920px before sending to API

Anthropic API rejects images exceeding 2000px in multi-image requests.
Compress images during upload to stay within limits while preserving
original aspect ratio and format (no webp conversion).

Fixes LOBE-6315

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: skip canvas compression for GIF and SVG images

Canvas serialization flattens animated GIFs and rasterizes SVGs.
Restrict compression to safe raster formats: JPEG, PNG, WebP.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: always compress images to PNG to avoid MIME mismatch

canvas.toDataURL with original file type can produce content that
doesn't match the declared MIME type, causing Anthropic API errors.
Always output PNG which is universally supported and consistent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* 🐛 fix: progressively shrink images to stay under 5MB API limit

If compressed PNG still exceeds 5MB, progressively reduce dimensions
by 20% until it fits. Also triggers compression for small-dimension
images that exceed 5MB file size.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ♻️ refactor: extract compressImageFile to utils and add comprehensive tests

Move compressImageFile, COMPRESSIBLE_IMAGE_TYPES, and constants to
@lobechat/utils/compressImage for reusability and testability.
Add tests for: dimension compression, file size limit, format filtering,
error handling, and progressive shrinking.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:23:58 +08:00
Innei 995d5ea354 🐛 fix(conversation): preserve mention runtime context (#13223)
* 🐛 fix(conversation): preserve mention context on retry

* 🐛 fix(runtime): preserve initial payload for mention context

*  feat(store): expose Zustand stores on window.__LOBE_STORES in dev

Made-with: Cursor
2026-03-24 19:50:26 +08:00
Arvin Xu 72ba8c8923 🐛 fix: add document parsing to knowledge base chunking pipeline (#13221)
* 🐛 fix: add document parsing to knowledge base chunking pipeline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix plugin title

* update

* 🐛 fix: add missing findByFileId mock in document service tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 19:49:26 +08:00
YuTengjing 6f65b1e65e feat: improve model switch panel with provider settings shortcut and default highlight (#13220) 2026-03-24 16:30:38 +08:00
YuTengjing 383caceb77 ♻️ refactor: rename getBusinessMenuItems to useBusinessMenuItems hook (#13219) 2026-03-24 15:58:29 +08:00
Rdmclin2 b4862f2942 🐛 fix: manual tool disabled (#13218)
fix: manual tool disabled
2026-03-24 15:24:18 +08:00
YuTengjing d1affa8e44 🌐 feat(i18n): add userPanel.upgradePlan i18n key (#13213) 2026-03-24 15:20:34 +08:00
Innei 6e3053fcb3 feat(cli): add generated man pages (#13200) 2026-03-24 14:46:56 +08:00
Innei b845ba4476 🔨 chore(vite): support direct markdown imports (#13216)
 feat(vite): support markdown imports
2026-03-24 14:33:57 +08:00
LiJian 7c00650be5 ♻️ refactor: add the user creds modules & skill should auto inject the need creds (#13124)
* feat: add the user creds modules & skill should auto inject the need creds

* feat: add the builtin creds tools

* fix: add some prompt in creds & codesandbox

* fix: open this settings/creds in community plan

* fix: refacoter the settings/creds the ui

* feat: improve the tools inject system Role

* feat: change the settings/creds mananger ui

* fix: add the creds upload Files api

* feat: should call back the files creds url
2026-03-24 14:28:23 +08:00
Innei 5bc015a746 🐛 fix: move nodrag from TabBar container to individual TabItems (#13211) 2026-03-24 11:33:00 +08:00
Arvin Xu 6757e10ec2 🐛 fix: map unsupported time_range values for Search1API (#13208)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:22:04 +08:00
Arvin Xu 48428594c3 🐛 fix: correct Search1API response parsing to match actual API format (#13207)
* 🐛 fix: correct Search1API response parsing to match actual API format

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix tests

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 02:18:28 +08:00
Innei 6a45414b46 🐛 fix(electron): reserve titlebar control space (#13204)
* 🐛 fix(electron): reserve titlebar control space

* 🐛 fix(electron): update titlebar padding for Windows control space
2026-03-23 23:29:55 +08:00
Arvin Xu 0f53490633 🐛 fix: fix anthropic claude model max window tokens (#13206)
* fix anthropic max tokens

* fix anthropic max tokens

* clean

* fix tests
2026-03-23 23:01:31 +08:00
lobehubbot b53abaa3b2 🔖 chore(release): release version v2.1.44 [skip ci] 2026-03-20 10:39:27 +00:00
685 changed files with 60112 additions and 3098 deletions
+69 -4
View File
@@ -200,20 +200,85 @@ The base directory (`~/.lobehub/`) can be overridden with the `LOBEHUB_CLI_HOME`
## Development
### Running in Dev Mode
Dev mode uses `LOBEHUB_CLI_HOME=.lobehub-dev` to isolate credentials from the global `~/.lobehub/` directory, so dev and production configs never conflict.
```bash
# Run directly (dev mode, uses ~/.lobehub-dev for credentials)
# Run a command in dev mode (from apps/cli/)
cd apps/cli && bun run dev -- <command>
# Build
# This is equivalent to:
LOBEHUB_CLI_HOME=.lobehub-dev bun src/index.ts <command>
```
### Connecting to Local Dev Server
To test CLI against a local dev server (e.g. `localhost:3011`):
**Step 1: Start the local server**
```bash
# From cloud repo root
bun run dev
# Server starts on http://localhost:3011 (or configured port)
```
**Step 2: Login to local server via Device Code Flow**
```bash
cd apps/cli && bun run dev -- login --server http://localhost:3011
```
This will:
1. Call `POST http://localhost:3011/oidc/device/auth` to get a device code
2. Print a URL like `http://localhost:3011/oidc/device?user_code=XXXX-YYYY`
3. Open the URL in your browser — log in and authorize
4. Save credentials to `apps/cli/.lobehub-dev/credentials.json`
5. Save server URL to `apps/cli/.lobehub-dev/settings.json`
After login, all subsequent `bun run dev -- <command>` calls will use the local server.
**Step 3: Run commands against local server**
```bash
cd apps/cli && bun run dev -- task list
cd apps/cli && bun run dev -- task create -i "Test task" -n "My Task"
cd apps/cli && bun run dev -- agent list
```
**Troubleshooting:**
- If login returns `invalid_grant`, make sure the local OIDC provider is properly configured (check `OIDC_*` env vars in `.env`)
- If you get `UNAUTHORIZED` on API calls, your token may have expired — run `bun run dev -- login --server http://localhost:3011` again
- Dev credentials are stored in `apps/cli/.lobehub-dev/` (gitignored), not in `~/.lobehub/`
### Switching Between Local and Production
```bash
# Dev mode (local server) — uses .lobehub-dev/
cd apps/cli && bun run dev -- <command>
# Production (app.lobehub.com) — uses ~/.lobehub/
lh <command>
```
The two environments are completely isolated by different credential directories.
### Build & Test
```bash
# Build CLI
cd apps/cli && bun run build
# Test (unit tests)
# Unit tests
cd apps/cli && bun run test
# E2E tests (requires authenticated CLI)
cd apps/cli && bunx vitest run e2e/kb.e2e.test.ts
# Link globally for testing
# Link globally for testing (installs lh/lobe/lobehub commands)
cd apps/cli && bun run cli:link
```
+4
View File
@@ -37,6 +37,10 @@ description: 'Code review checklist for LobeHub. Use when reviewing PRs, diffs,
- Keys added to `src/locales/default/{namespace}.ts` with `{feature}.{context}.{action|status}` naming
- For PRs: `locales/` translations for all languages updated (`pnpm i18n`)
### SPA / routing
- **`desktopRouter` pair:** If the diff touches `src/spa/router/desktopRouter.config.tsx`, does it also update `src/spa/router/desktopRouter.config.desktop.tsx` with the same route paths and nesting? Single-file edits often cause drift and blank screens.
### Reuse
- Newly written code duplicates existing utilities in `packages/utils` or shared modules?
+2 -6
View File
@@ -101,10 +101,6 @@ DROP TABLE "old_table";
CREATE INDEX "users_email_idx" ON "users" ("email");
```
## Step 4: Regenerate Client After SQL Edits
## Step 4: Update Journal Tag
After modifying the generated SQL (e.g., adding `IF NOT EXISTS`), regenerate the client:
```bash
bun run db:generate:client
```
After renaming the migration SQL file in Step 2, update the `tag` field in `packages/database/migrations/meta/_journal.json` to match the new filename (without `.sql` extension).
+15 -2
View File
@@ -32,15 +32,28 @@ Hybrid routing: Next.js App Router (static pages) + React Router DOM (main SPA).
| Route Type | Use Case | Implementation |
| ------------------ | --------------------------------- | ---------------------------- |
| Next.js App Router | Auth pages (login, signup, oauth) | `src/app/[variants]/(auth)/` |
| React Router DOM | Main SPA (chat, settings) | `desktopRouter.config.tsx` |
| React Router DOM | Main SPA (chat, settings) | `desktopRouter.config.tsx` + `desktopRouter.config.desktop.tsx` (must match) |
### Key Files
- Entry: `src/spa/entry.web.tsx` (web), `src/spa/entry.mobile.tsx`, `src/spa/entry.desktop.tsx`
- Desktop router: `src/spa/router/desktopRouter.config.tsx`
- Desktop router (pair — **always edit both** when changing routes): `src/spa/router/desktopRouter.config.tsx` (dynamic imports) and `src/spa/router/desktopRouter.config.desktop.tsx` (sync imports). Drift can cause unregistered routes / blank screen.
- Mobile router: `src/spa/router/mobileRouter.config.tsx`
- Router utilities: `src/utils/router.tsx`
### `.desktop.{ts,tsx}` File Sync Rule
**CRITICAL**: Some files have a `.desktop.ts(x)` variant that Electron uses instead of the base file. When editing a base file, **always check** if a `.desktop` counterpart exists and update it in sync. Drift causes blank pages or missing features in Electron.
Known pairs that must stay in sync:
| Base file (web, dynamic imports) | Desktop file (Electron, sync imports) |
| --- | --- |
| `src/spa/router/desktopRouter.config.tsx` | `src/spa/router/desktopRouter.config.desktop.tsx` |
| `src/routes/(main)/settings/features/componentMap.ts` | `src/routes/(main)/settings/features/componentMap.desktop.ts` |
**How to check**: After editing any `.ts` / `.tsx` file, run `Glob` for `<filename>.desktop.{ts,tsx}` in the same directory. If a match exists, update it with the equivalent sync-import change.
### Router Utilities
```tsx
+18 -3
View File
@@ -1,6 +1,6 @@
---
name: spa-routes
description: SPA route and feature structure. Use when adding or modifying SPA routes in src/routes, defining new route segments, or moving route logic into src/features. Covers how to keep routes thin and how to divide files between routes and features.
description: MUST use when editing src/routes/ segments, src/spa/router/desktopRouter.config.tsx or desktopRouter.config.desktop.tsx (always change both together), mobileRouter.config.tsx, or when moving UI/logic between routes and src/features/.
---
# SPA Routes and Features Guide
@@ -13,6 +13,8 @@ SPA structure:
This project uses a **roots vs features** split: `src/routes/` only holds page segments; business logic and UI live in `src/features/` by domain.
**Agent constraint — desktop router parity:** Edits to the desktop route tree must update **both** `src/spa/router/desktopRouter.config.tsx` and `src/spa/router/desktopRouter.config.desktop.tsx` in the same change (same paths, nesting, index routes, and segment registration). Updating only one causes drift; the missing tree can fail to register routes and surface as a **blank screen** or broken navigation on the affected build.
## When to Use This Skill
- Adding a new SPA route or route segment
@@ -73,8 +75,21 @@ Each feature should:
- Layout: `export { default } from '@/features/MyFeature/MyLayout'` or compose a few feature components + `<Outlet />`.
- Page: import from `@/features/MyFeature` (or a specific subpath) and render; no business logic in the route file.
5. **Register the route**
- Add the segment to `src/spa/router/desktopRouter.config.tsx` (or the right router config) with `dynamicElement` / `dynamicLayout` pointing at the new route paths (e.g. `@/routes/(main)/my-feature`).
5. **Register the route (desktop — two files, always)**
- **`desktopRouter.config.tsx`:** Add the segment with `dynamicElement` / `dynamicLayout` pointing at route modules (e.g. `@/routes/(main)/my-feature`).
- **`desktopRouter.config.desktop.tsx`:** Mirror the **same** `RouteObject` shape: identical `path` / `index` / parent-child structure. Use the static imports and elements already used in that file (see neighboring routes). Do **not** register in only one of these files.
- **Mobile-only flows:** use `mobileRouter.config.tsx` instead (no need to duplicate into the desktop pair unless the route truly exists on both).
---
## 3a. Desktop router pair (`desktopRouter.config` × 2)
| File | Role |
|------|------|
| `desktopRouter.config.tsx` | Dynamic imports via `dynamicElement` / `dynamicLayout` — code-splitting; used by `entry.web.tsx` and `entry.desktop.tsx`. |
| `desktopRouter.config.desktop.tsx` | Same route tree with **synchronous** imports — kept for Electron / local parity and predictable bundling. |
Anything that changes the tree (new segment, renamed `path`, moved layout, new child route) must be reflected in **both** files in one PR or commit. Remove routes from both when deleting.
---
+123
View File
@@ -0,0 +1,123 @@
---
name: trpc-router
description: TRPC router development guide. Use when creating or modifying TRPC routers (src/server/routers/**), adding procedures, or working with server-side API endpoints. Triggers on TRPC router creation, procedure implementation, or API endpoint tasks.
---
# TRPC Router Guide
## File Location
- Routers: `src/server/routers/lambda/<domain>.ts`
- Helpers: `src/server/routers/lambda/_helpers/`
- Schemas: `src/server/routers/lambda/_schema/`
## Router Structure
### Imports
```typescript
import { TRPCError } from '@trpc/server';
import { z } from 'zod';
import { SomeModel } from '@/database/models/some';
import { authedProcedure, router } from '@/libs/trpc/lambda';
import { serverDatabase } from '@/libs/trpc/lambda/middleware';
```
### Middleware: Inject Models into ctx
**Always use middleware to inject models into `ctx`** instead of creating `new Model(ctx.serverDB, ctx.userId)` inside every procedure.
```typescript
const domainProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
const { ctx } = opts;
return opts.next({
ctx: {
fooModel: new FooModel(ctx.serverDB, ctx.userId),
barModel: new BarModel(ctx.serverDB, ctx.userId),
},
});
});
```
Then use `ctx.fooModel` in procedures:
```typescript
// Good
const model = ctx.fooModel;
// Bad - don't create models inside procedures
const model = new FooModel(ctx.serverDB, ctx.userId);
```
**Exception**: When a model needs a different `userId` (e.g., watchdog iterating over multiple users' tasks), create it inline.
### Procedure Pattern
```typescript
export const fooRouter = router({
// Query
find: domainProcedure.input(z.object({ id: z.string() })).query(async ({ input, ctx }) => {
try {
const item = await ctx.fooModel.findById(input.id);
if (!item) throw new TRPCError({ code: 'NOT_FOUND', message: 'Not found' });
return { data: item, success: true };
} catch (error) {
if (error instanceof TRPCError) throw error;
console.error('[foo:find]', error);
throw new TRPCError({
cause: error,
code: 'INTERNAL_SERVER_ERROR',
message: 'Failed to find item',
});
}
}),
// Mutation
create: domainProcedure.input(createSchema).mutation(async ({ input, ctx }) => {
try {
const item = await ctx.fooModel.create(input);
return { data: item, message: 'Created', success: true };
} catch (error) {
if (error instanceof TRPCError) throw error;
console.error('[foo:create]', error);
throw new TRPCError({
cause: error,
code: 'INTERNAL_SERVER_ERROR',
message: 'Failed to create',
});
}
}),
});
```
### Aggregated Detail Endpoint
For views that need multiple related data, create a single `detail` procedure that fetches everything in parallel:
```typescript
detail: domainProcedure.input(idInput).query(async ({ input, ctx }) => {
const item = await resolveOrThrow(ctx.fooModel, input.id);
const [children, related] = await Promise.all([
ctx.fooModel.findChildren(item.id),
ctx.barModel.findByFooId(item.id),
]);
return {
data: { ...item, children, related },
success: true,
};
}),
```
This avoids the CLI or frontend making N sequential requests.
## Conventions
- Return shape: `{ data, success: true }` for queries, `{ data?, message, success: true }` for mutations
- Error handling: re-throw `TRPCError`, wrap others with `console.error` + new `TRPCError`
- Input validation: use `zod` schemas, define at file top
- Router name: `export const fooRouter = router({ ... })`
- Procedure names: alphabetical order within the router object
- Log prefix: `[domain:procedure]` format, e.g. `[task:create]`
+58
View File
@@ -2,6 +2,64 @@
# Changelog
### [Version 2.1.45](https://github.com/lobehub/lobe-chat/compare/v2.1.44...v2.1.45)
<sup>Released on **2026-03-26**</sup>
#### 👷 Build System
- **misc**: add agent task system database schema.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### Build System
- **misc**: add agent task system database schema, closes [#13280](https://github.com/lobehub/lobe-chat/issues/13280) ([b005a9c](https://github.com/lobehub/lobe-chat/commit/b005a9c))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 2.1.44](https://github.com/lobehub/lobe-chat/compare/v2.2.0-nightly.202603200623...v2.1.44)
<sup>Released on **2026-03-20**</sup>
#### 🐛 Bug Fixes
- **misc**: misc UI/UX improvements and bug fixes.
#### 💄 Styles
- **misc**: add image/video switch.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **misc**: misc UI/UX improvements and bug fixes, closes [#13153](https://github.com/lobehub/lobe-chat/issues/13153) ([abd152b](https://github.com/lobehub/lobe-chat/commit/abd152b))
#### Styles
- **misc**: add image/video switch, closes [#13152](https://github.com/lobehub/lobe-chat/issues/13152) ([2067cb2](https://github.com/lobehub/lobe-chat/commit/2067cb2))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 2.1.43](https://github.com/lobehub/lobe-chat/compare/v2.1.42...v2.1.43)
<sup>Released on **2026-03-16**</sup>
+160
View File
@@ -0,0 +1,160 @@
.\" Code generated by `npm run man:generate`; DO NOT EDIT.
.\" Manual command details come from the Commander command tree.
.TH LH 1 "" "@lobehub/cli 0.0.1\-canary.12" "User Commands"
.SH NAME
lh \- LobeHub CLI \- manage and connect to LobeHub services
.SH SYNOPSIS
.B lh
[\fIOPTION\fR]...
[\fICOMMAND\fR]
.br
.B lobe
[\fIOPTION\fR]...
[\fICOMMAND\fR]
.br
.B lobehub
[\fIOPTION\fR]...
[\fICOMMAND\fR]
.SH DESCRIPTION
lh is the command\-line interface for LobeHub. It provides authentication, device gateway connectivity, content generation, resource search, and management commands for agents, files, models, providers, plugins, knowledge bases, threads, topics, and related resources.
.PP
For command-specific manuals, use the built-in manual command:
.PP
.RS
.B lh man
[\fICOMMAND\fR]...
.RE
.SH COMMANDS
.TP
.B login
Log in to LobeHub via browser (Device Code Flow)
.TP
.B logout
Log out and remove stored credentials
.TP
.B completion
Output shell completion script
.TP
.B man
Show a manual page for the CLI or a subcommand
.TP
.B connect
Connect to the device gateway and listen for tool calls
.TP
.B device
Manage connected devices
.TP
.B status
Check if gateway connection can be established
.TP
.B doc
Manage documents
.TP
.B search
Search across local resources or the web
.TP
.B kb
Manage knowledge bases, folders, documents, and files
.TP
.B memory
Manage user memories
.TP
.B agent
Manage agents
.TP
.B agent\-group
Manage agent groups
.TP
.B bot
Manage bot integrations
.TP
.B cron
Manage agent cron jobs
.TP
.B generate
Generate content (text, image, video, speech) Alias: gen.
.TP
.B file
Manage files
.TP
.B skill
Manage agent skills
.TP
.B session\-group
Manage agent session groups
.TP
.B thread
Manage message threads
.TP
.B topic
Manage conversation topics
.TP
.B message
Manage messages
.TP
.B model
Manage AI models
.TP
.B provider
Manage AI providers
.TP
.B plugin
Manage plugins
.TP
.B user
Manage user account and settings
.TP
.B whoami
Display current user information
.TP
.B usage
View usage statistics
.TP
.B eval
Manage evaluation workflows
.SH OPTIONS
.TP
.B \-V, \-\-version
output the version number
.TP
.B \-h, \-\-help
display help for command
.SH FILES
.TP
.I ~/.lobehub/credentials.json
Encrypted access and refresh tokens.
.TP
.I ~/.lobehub/settings.json
CLI settings such as server and gateway URLs.
.TP
.I ~/.lobehub/daemon.pid
Background daemon PID file.
.TP
.I ~/.lobehub/daemon.status
Background daemon status metadata.
.TP
.I ~/.lobehub/daemon.log
Background daemon log output.
.PP
The base directory can be overridden with the
.B LOBEHUB_CLI_HOME
environment variable.
.SH EXAMPLES
.TP
.B lh login
Start interactive login in the browser.
.TP
.B lh connect \-\-daemon
Start the device gateway connection in the background.
.TP
.B lh search \-q "gpt\-5"
Search local resources for a query.
.TP
.B lh generate text "Write release notes"
Generate text from a prompt.
.TP
.B lh man generate
Show the built\-in manual for the generate command group.
.SH SEE ALSO
.BR lobe (1),
.BR lobehub (1)
+1
View File
@@ -0,0 +1 @@
.so man1/lh.1
+1
View File
@@ -0,0 +1 @@
.so man1/lh.1
+10 -3
View File
@@ -1,21 +1,28 @@
{
"name": "@lobehub/cli",
"version": "0.0.1-canary.12",
"version": "0.0.1-canary.14",
"type": "module",
"bin": {
"lh": "./dist/index.js",
"lobe": "./dist/index.js",
"lobehub": "./dist/index.js"
},
"man": [
"./man/man1/lh.1",
"./man/man1/lobe.1",
"./man/man1/lobehub.1"
],
"files": [
"dist"
"dist",
"man"
],
"scripts": {
"build": "tsdown",
"cli:link": "bun link",
"cli:unlink": "bun unlink",
"dev": "LOBEHUB_CLI_HOME=.lobehub-dev bun src/index.ts",
"prepublishOnly": "npm run build",
"man:generate": "bun src/man/generate.ts",
"prepublishOnly": "npm run build && npm run man:generate",
"test": "bunx vitest run --config vitest.config.mts --silent='passed-only'",
"test:coverage": "bunx vitest run --config vitest.config.mts --coverage",
"type-check": "tsc --noEmit"
+28 -14
View File
@@ -5,8 +5,8 @@ import type { LambdaRouter } from '@/server/routers/lambda';
import type { ToolsRouter } from '@/server/routers/tools';
import { getValidToken } from '../auth/refresh';
import { OFFICIAL_SERVER_URL } from '../constants/urls';
import { loadSettings } from '../settings';
import { CLI_API_KEY_ENV } from '../constants/auth';
import { resolveServerUrl } from '../settings';
import { log } from '../utils/logger';
export type TrpcClient = ReturnType<typeof createTRPCClient<LambdaRouter>>;
@@ -19,31 +19,46 @@ async function getAuthAndServer() {
// LOBEHUB_JWT + LOBEHUB_SERVER env vars (used by server-side sandbox execution)
const envJwt = process.env.LOBEHUB_JWT;
if (envJwt) {
const serverUrl = process.env.LOBEHUB_SERVER || OFFICIAL_SERVER_URL;
return { accessToken: envJwt, serverUrl: serverUrl.replace(/\/$/, '') };
const serverUrl = resolveServerUrl();
return {
headers: { 'Oidc-Auth': envJwt },
serverUrl,
};
}
const envApiKey = process.env[CLI_API_KEY_ENV];
if (envApiKey) {
const serverUrl = resolveServerUrl();
return {
headers: { 'X-API-Key': envApiKey },
serverUrl,
};
}
const result = await getValidToken();
if (!result) {
log.error("No authentication found. Run 'lh login' first.");
log.error(`No authentication found. Run 'lh login' first, or set ${CLI_API_KEY_ENV}.`);
process.exit(1);
}
const accessToken = result.credentials.accessToken;
const serverUrl = loadSettings()?.serverUrl || OFFICIAL_SERVER_URL;
const serverUrl = resolveServerUrl();
return { accessToken, serverUrl: serverUrl.replace(/\/$/, '') };
return {
headers: { 'Oidc-Auth': result.credentials.accessToken },
serverUrl,
};
}
export async function getTrpcClient(): Promise<TrpcClient> {
if (_client) return _client;
const { accessToken, serverUrl } = await getAuthAndServer();
const { headers, serverUrl } = await getAuthAndServer();
_client = createTRPCClient<LambdaRouter>({
links: [
httpLink({
headers: { 'Oidc-Auth': accessToken },
headers,
transformer: superjson,
url: `${serverUrl}/trpc/lambda`,
}),
@@ -56,12 +71,11 @@ export async function getTrpcClient(): Promise<TrpcClient> {
export async function getToolsTrpcClient(): Promise<ToolsTrpcClient> {
if (_toolsClient) return _toolsClient;
const { accessToken, serverUrl } = await getAuthAndServer();
const { headers, serverUrl } = await getAuthAndServer();
_toolsClient = createTRPCClient<ToolsRouter>({
links: [
httpLink({
headers: { 'Oidc-Auth': accessToken },
headers,
transformer: superjson,
url: `${serverUrl}/trpc/tools`,
}),
+11 -4
View File
@@ -1,6 +1,6 @@
import { getValidToken } from '../auth/refresh';
import { OFFICIAL_SERVER_URL } from '../constants/urls';
import { loadSettings } from '../settings';
import { CLI_API_KEY_ENV } from '../constants/auth';
import { resolveServerUrl } from '../settings';
import { log } from '../utils/logger';
// Must match the server's SECRET_XOR_KEY (src/envs/auth.ts)
@@ -33,12 +33,19 @@ export interface AuthInfo {
export async function getAuthInfo(): Promise<AuthInfo> {
const result = await getValidToken();
if (!result) {
if (process.env[CLI_API_KEY_ENV]) {
log.error(
`API key auth from ${CLI_API_KEY_ENV} is not supported for /webapi/* routes. Run OIDC login instead.`,
);
process.exit(1);
}
log.error("No authentication found. Run 'lh login' first.");
process.exit(1);
}
const accessToken = result!.credentials.accessToken;
const serverUrl = loadSettings()?.serverUrl || OFFICIAL_SERVER_URL;
const serverUrl = resolveServerUrl();
return {
accessToken,
@@ -47,6 +54,6 @@ export async function getAuthInfo(): Promise<AuthInfo> {
'Oidc-Auth': accessToken,
'X-lobe-chat-auth': obfuscatePayloadWithXOR({}),
},
serverUrl: serverUrl.replace(/\/$/, ''),
serverUrl,
};
}
+41
View File
@@ -0,0 +1,41 @@
import { normalizeUrl, resolveServerUrl } from '../settings';
interface CurrentUserResponse {
data?: {
id?: string;
userId?: string;
};
error?: string;
message?: string;
success?: boolean;
}
export async function getUserIdFromApiKey(apiKey: string, serverUrl?: string): Promise<string> {
const normalizedServerUrl = normalizeUrl(serverUrl) || resolveServerUrl();
const response = await fetch(`${normalizedServerUrl}/api/v1/users/me`, {
headers: {
Authorization: `Bearer ${apiKey}`,
},
});
let body: CurrentUserResponse | undefined;
try {
body = (await response.json()) as CurrentUserResponse;
} catch {
throw new Error(`Failed to parse response from ${normalizedServerUrl}/api/v1/users/me.`);
}
if (!response.ok || body?.success === false) {
throw new Error(
body?.error || body?.message || `Request failed with status ${response.status}.`,
);
}
const userId = body?.data?.id || body?.data?.userId;
if (!userId) {
throw new Error('Current user response did not include a user id.');
}
return userId;
}
+2 -3
View File
@@ -1,5 +1,4 @@
import { OFFICIAL_SERVER_URL } from '../constants/urls';
import { loadSettings } from '../settings';
import { resolveServerUrl } from '../settings';
import { loadCredentials, saveCredentials, type StoredCredentials } from './credentials';
const CLIENT_ID = 'lobehub-cli';
@@ -20,7 +19,7 @@ export async function getValidToken(): Promise<{ credentials: StoredCredentials
// Token expired — try refresh
if (!credentials.refreshToken) return null;
const serverUrl = loadSettings()?.serverUrl || OFFICIAL_SERVER_URL;
const serverUrl = resolveServerUrl();
const refreshed = await refreshAccessToken(serverUrl, credentials.refreshToken);
if (!refreshed) return null;
+68 -4
View File
@@ -1,12 +1,21 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { getUserIdFromApiKey } from './apiKey';
import { getValidToken } from './refresh';
import { resolveToken } from './resolveToken';
vi.mock('./apiKey', () => ({
getUserIdFromApiKey: vi.fn(),
}));
vi.mock('./refresh', () => ({
getValidToken: vi.fn(),
}));
vi.mock('../settings', () => ({
loadSettings: vi.fn().mockReturnValue({ serverUrl: 'https://app.lobehub.com' }),
resolveServerUrl: vi.fn(() =>
(process.env.LOBEHUB_SERVER || 'https://app.lobehub.com').replace(/\/$/, ''),
),
}));
vi.mock('../utils/logger', () => ({
log: {
debug: vi.fn(),
@@ -25,14 +34,23 @@ function makeJwt(sub: string): string {
describe('resolveToken', () => {
let exitSpy: ReturnType<typeof vi.spyOn>;
const originalApiKey = process.env.LOBEHUB_CLI_API_KEY;
const originalJwt = process.env.LOBEHUB_JWT;
const originalServer = process.env.LOBEHUB_SERVER;
beforeEach(() => {
exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => {
throw new Error('process.exit');
});
delete process.env.LOBEHUB_CLI_API_KEY;
delete process.env.LOBEHUB_JWT;
delete process.env.LOBEHUB_SERVER;
});
afterEach(() => {
process.env.LOBEHUB_CLI_API_KEY = originalApiKey;
process.env.LOBEHUB_JWT = originalJwt;
process.env.LOBEHUB_SERVER = originalServer;
exitSpy.mockRestore();
});
@@ -42,7 +60,12 @@ describe('resolveToken', () => {
const result = await resolveToken({ token });
expect(result).toEqual({ token, userId: 'user-123' });
expect(result).toEqual({
serverUrl: 'https://app.lobehub.com',
token,
tokenType: 'jwt',
userId: 'user-123',
});
});
it('should exit if JWT has no sub claim', async () => {
@@ -67,7 +90,12 @@ describe('resolveToken', () => {
userId: 'user-456',
});
expect(result).toEqual({ token: 'svc-token', userId: 'user-456' });
expect(result).toEqual({
serverUrl: 'https://app.lobehub.com',
token: 'svc-token',
tokenType: 'serviceToken',
userId: 'user-456',
});
});
it('should exit if --user-id is not provided', async () => {
@@ -76,6 +104,37 @@ describe('resolveToken', () => {
});
});
describe('with environment api key', () => {
it('should return API key from environment', async () => {
process.env.LOBEHUB_CLI_API_KEY = 'sk-lh-test';
vi.mocked(getUserIdFromApiKey).mockResolvedValue('user-789');
const result = await resolveToken({});
expect(getUserIdFromApiKey).toHaveBeenCalledWith('sk-lh-test', 'https://app.lobehub.com');
expect(result).toEqual({
serverUrl: 'https://app.lobehub.com',
token: 'sk-lh-test',
tokenType: 'apiKey',
userId: 'user-789',
});
});
it('should prefer LOBEHUB_SERVER when validating the API key', async () => {
process.env.LOBEHUB_CLI_API_KEY = 'sk-lh-test';
process.env.LOBEHUB_SERVER = 'https://self-hosted.example.com/';
vi.mocked(getUserIdFromApiKey).mockResolvedValue('user-789');
const result = await resolveToken({});
expect(getUserIdFromApiKey).toHaveBeenCalledWith(
'sk-lh-test',
'https://self-hosted.example.com',
);
expect(result.serverUrl).toBe('https://self-hosted.example.com');
});
});
describe('with stored credentials', () => {
it('should return stored credentials token', async () => {
const token = makeJwt('stored-user');
@@ -87,7 +146,12 @@ describe('resolveToken', () => {
const result = await resolveToken({});
expect(result).toEqual({ token, userId: 'stored-user' });
expect(result).toEqual({
serverUrl: 'https://app.lobehub.com',
token,
tokenType: 'jwt',
userId: 'stored-user',
});
});
it('should exit if stored token has no sub', async () => {
+38 -8
View File
@@ -1,4 +1,7 @@
import { CLI_API_KEY_ENV } from '../constants/auth';
import { resolveServerUrl } from '../settings';
import { log } from '../utils/logger';
import { getUserIdFromApiKey } from './apiKey';
import { getValidToken } from './refresh';
interface ResolveTokenOptions {
@@ -8,7 +11,9 @@ interface ResolveTokenOptions {
}
interface ResolvedAuth {
serverUrl: string;
token: string;
tokenType: 'apiKey' | 'jwt' | 'serviceToken';
userId: string;
}
@@ -25,20 +30,21 @@ function parseJwtSub(token: string): string | undefined {
}
/**
* Resolve an access token from explicit options or stored credentials.
* Resolve an access token from explicit options, environment variables, or stored credentials.
* Exits the process if no token can be resolved.
*/
export async function resolveToken(options: ResolveTokenOptions): Promise<ResolvedAuth> {
// LOBEHUB_JWT env var takes highest priority (used by server-side sandbox execution)
const envJwt = process.env.LOBEHUB_JWT;
if (envJwt) {
const serverUrl = resolveServerUrl();
const userId = parseJwtSub(envJwt);
if (!userId) {
log.error('Could not extract userId from LOBEHUB_JWT.');
process.exit(1);
}
log.debug('Using LOBEHUB_JWT from environment');
return { token: envJwt, userId };
return { serverUrl, token: envJwt, tokenType: 'jwt', userId };
}
// Explicit token takes priority
@@ -48,7 +54,7 @@ export async function resolveToken(options: ResolveTokenOptions): Promise<Resolv
log.error('Could not extract userId from token. Provide --user-id explicitly.');
process.exit(1);
}
return { token: options.token, userId };
return { serverUrl: resolveServerUrl(), token: options.token, tokenType: 'jwt', userId };
}
if (options.serviceToken) {
@@ -56,22 +62,46 @@ export async function resolveToken(options: ResolveTokenOptions): Promise<Resolv
log.error('--user-id is required when using --service-token');
process.exit(1);
}
return { token: options.serviceToken, userId: options.userId };
return {
serverUrl: resolveServerUrl(),
token: options.serviceToken,
tokenType: 'serviceToken',
userId: options.userId,
};
}
const envApiKey = process.env[CLI_API_KEY_ENV];
if (envApiKey) {
try {
const serverUrl = resolveServerUrl();
const userId = await getUserIdFromApiKey(envApiKey, serverUrl);
log.debug(`Using ${CLI_API_KEY_ENV} from environment`);
return { serverUrl, token: envApiKey, tokenType: 'apiKey', userId };
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
log.error(`Failed to validate ${CLI_API_KEY_ENV}: ${message}`);
process.exit(1);
}
}
// Try stored credentials
const result = await getValidToken();
if (result) {
log.debug('Using stored credentials');
const token = result.credentials.accessToken;
const userId = parseJwtSub(token);
const { credentials } = result;
const serverUrl = resolveServerUrl();
const userId = parseJwtSub(credentials.accessToken);
if (!userId) {
log.error("Stored token is invalid. Run 'lh login' again.");
process.exit(1);
}
return { token, userId };
return { serverUrl, token: credentials.accessToken, tokenType: 'jwt', userId };
}
log.error("No authentication found. Run 'lh login' first, or provide --token.");
log.error(
`No authentication found. Run 'lh login' first, or set ${CLI_API_KEY_ENV}, or provide --token.`,
);
process.exit(1);
}
+211
View File
@@ -0,0 +1,211 @@
import type { Command } from 'commander';
import pc from 'picocolors';
import { getTrpcClient } from '../api/client';
import { outputJson, printTable, timeAgo, truncate } from '../utils/format';
import { log } from '../utils/logger';
export function registerBriefCommand(program: Command) {
const brief = program.command('brief').description('Manage briefs (Agent reports)');
// ── list ──────────────────────────────────────────────
brief
.command('list')
.description('List briefs')
.option('--unresolved', 'Only show unresolved briefs (default)')
.option('--all', 'Show all briefs')
.option('--type <type>', 'Filter by type (decision/result/insight/error)')
.option('-L, --limit <n>', 'Page size', '50')
.option('--json [fields]', 'Output JSON')
.action(
async (options: {
all?: boolean;
json?: string | boolean;
limit?: string;
type?: string;
unresolved?: boolean;
}) => {
const client = await getTrpcClient();
let items: any[];
if (options.all) {
const input: Record<string, any> = {};
if (options.type) input.type = options.type;
if (options.limit) input.limit = Number.parseInt(options.limit, 10);
const result = await client.brief.list.query(input as any);
items = result.data;
} else {
const result = await client.brief.listUnresolved.query();
items = result.data;
}
if (options.json !== undefined) {
outputJson(items, typeof options.json === 'string' ? options.json : undefined);
return;
}
if (!items || items.length === 0) {
log.info('No briefs found.');
return;
}
const rows = items.map((b: any) => [
typeBadge(b.type, b.priority),
truncate(b.title, 40),
truncate(b.summary, 50),
b.taskId ? pc.dim(b.taskId) : b.cronJobId ? pc.dim(b.cronJobId) : '-',
b.resolvedAt ? pc.green('resolved') : b.readAt ? pc.dim('read') : 'new',
timeAgo(b.createdAt),
]);
printTable(rows, ['TYPE', 'TITLE', 'SUMMARY', 'SOURCE', 'STATUS', 'CREATED']);
},
);
// ── view ──────────────────────────────────────────────
brief
.command('view <id>')
.description('View brief details (auto marks as read)')
.option('--json [fields]', 'Output JSON')
.action(async (id: string, options: { json?: string | boolean }) => {
const client = await getTrpcClient();
const result = await client.brief.find.query({ id });
const b = result.data;
if (options.json !== undefined) {
outputJson(b, typeof options.json === 'string' ? options.json : undefined);
return;
}
if (!b) {
log.error('Brief not found.');
return;
}
// Auto mark as read
if (!b.readAt) {
await client.brief.markRead.mutate({ id });
}
const resolvedLabel = b.resolvedAt
? (() => {
const actions = (b.actions as any[]) || [];
const matched = actions.find((a: any) => a.key === (b as any).resolvedAction);
return pc.green(` ${matched?.label || '✓ resolved'}`);
})()
: '';
console.log(`\n${typeBadge(b.type, b.priority)} ${pc.bold(b.title)}${resolvedLabel}`);
console.log(`${pc.dim('Type:')} ${b.type} ${pc.dim('Created:')} ${timeAgo(b.createdAt)}`);
if (b.agentId) console.log(`${pc.dim('Agent:')} ${b.agentId}`);
if (b.taskId) console.log(`${pc.dim('Task:')} ${b.taskId}`);
if (b.cronJobId) console.log(`${pc.dim('CronJob:')} ${b.cronJobId}`);
if (b.topicId) console.log(`${pc.dim('Topic:')} ${b.topicId}`);
console.log(`\n${b.summary}`);
if (b.artifacts && (b.artifacts as string[]).length > 0) {
console.log(`\n${pc.dim('Artifacts:')}`);
for (const a of b.artifacts as string[]) {
console.log(` 📎 ${a}`);
}
}
console.log();
if (!b.resolvedAt) {
const actions = (b.actions as any[]) || [];
if (actions.length > 0) {
console.log('Actions:');
for (const a of actions) {
const cmd =
a.type === 'comment'
? `lh brief resolve ${b.id} --action ${a.key} -m "内容"`
: `lh brief resolve ${b.id} --action ${a.key}`;
console.log(` ${a.label} ${pc.dim(cmd)}`);
}
} else {
console.log(pc.dim('Actions:'));
console.log(pc.dim(` lh brief resolve ${b.id} # 确认通过`));
console.log(pc.dim(` lh brief resolve ${b.id} --reply "修改意见" # 反馈修改`));
}
} else if ((b as any).resolvedComment) {
console.log(`${pc.dim('Comment:')} ${(b as any).resolvedComment}`);
}
});
// ── resolve ──────────────────────────────────────────────
brief
.command('resolve <id>')
.description('Resolve a brief (approve, reply, or custom action)')
.option('--action <key>', 'Execute a specific action (e.g. approve, feedback)')
.option('--reply <text>', 'Reply with feedback')
.option('-m, --message <text>', 'Message for comment-type actions')
.action(async (id: string, options: { action?: string; message?: string; reply?: string }) => {
const client = await getTrpcClient();
const actionKey = options.action || (options.reply ? 'feedback' : 'approve');
const actionMessage = options.message || options.reply;
const briefResult = await client.brief.find.query({ id });
const b = briefResult.data;
// For comment-type actions, add comment to task
if (actionMessage && b?.taskId) {
await client.task.addComment.mutate({
briefId: id,
content: actionMessage,
id: b.taskId,
});
}
await client.brief.resolve.mutate({
action: actionKey,
comment: actionMessage,
id,
});
const actions = (b?.actions as any[]) || [];
const matchedAction = actions.find((a: any) => a.key === actionKey);
const label = matchedAction?.label || actionKey;
log.info(`${label} — Brief ${pc.dim(id)} resolved.`);
});
// ── delete ──────────────────────────────────────────────
brief
.command('delete <id>')
.description('Delete a brief')
.action(async (id: string) => {
const client = await getTrpcClient();
await client.brief.delete.mutate({ id });
log.info(`Brief ${pc.dim(id)} deleted.`);
});
}
function typeBadge(type: string, priority?: string): string {
if (priority === 'urgent') {
return pc.red('🔴');
}
switch (type) {
case 'decision': {
return pc.yellow('🟡');
}
case 'result': {
return pc.green('✅');
}
case 'insight': {
return '💬';
}
case 'error': {
return pc.red('❌');
}
default: {
return '·';
}
}
}
+37 -2
View File
@@ -2,10 +2,16 @@ import { Command } from 'commander';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
vi.mock('../auth/resolveToken', () => ({
resolveToken: vi.fn().mockResolvedValue({ token: 'test-token', userId: 'test-user' }),
resolveToken: vi.fn().mockResolvedValue({
serverUrl: 'https://app.lobehub.com',
token: 'test-token',
tokenType: 'jwt',
userId: 'test-user',
}),
}));
vi.mock('../settings', () => ({
loadSettings: vi.fn().mockReturnValue(null),
normalizeUrl: vi.fn((url?: string) => (url ? url.replace(/\/$/, '') : undefined)),
saveSettings: vi.fn(),
}));
@@ -161,6 +167,12 @@ describe('connect command', () => {
serverUrl: 'https://self-hosted.example.com',
});
});
it('should pass the resolved serverUrl to GatewayClient', async () => {
const program = createProgram();
await program.parseAsync(['node', 'test', 'connect']);
expect(clientOptions.serverUrl).toBe('https://app.lobehub.com');
});
it('should handle tool call requests', async () => {
const program = createProgram();
@@ -208,7 +220,12 @@ describe('connect command', () => {
});
it('should handle auth_expired', async () => {
vi.mocked(resolveToken).mockResolvedValueOnce({ token: 'new-tok', userId: 'user' });
vi.mocked(resolveToken).mockResolvedValueOnce({
serverUrl: 'https://app.lobehub.com',
token: 'new-tok',
tokenType: 'jwt',
userId: 'user',
});
const program = createProgram();
await program.parseAsync(['node', 'test', 'connect']);
@@ -220,6 +237,24 @@ describe('connect command', () => {
expect(exitSpy).toHaveBeenCalledWith(1);
});
it('should ignore auth_expired for api key auth', async () => {
vi.mocked(resolveToken).mockResolvedValueOnce({
serverUrl: 'https://self-hosted.example.com',
token: 'test-api-key',
tokenType: 'apiKey',
userId: 'user',
});
const program = createProgram();
await program.parseAsync(['node', 'test', 'connect']);
await clientEventHandlers['auth_expired']?.();
expect(log.error).not.toHaveBeenCalled();
expect(cleanupAllProcesses).not.toHaveBeenCalled();
expect(exitSpy).not.toHaveBeenCalled();
});
it('should handle error event', async () => {
const program = createProgram();
await program.parseAsync(['node', 'test', 'connect']);
+13 -4
View File
@@ -11,6 +11,7 @@ import { GatewayClient } from '@lobechat/device-gateway-client';
import type { Command } from 'commander';
import { resolveToken } from '../auth/resolveToken';
import { CLI_API_KEY_ENV } from '../constants/auth';
import { OFFICIAL_GATEWAY_URL } from '../constants/urls';
import {
appendLog,
@@ -23,7 +24,7 @@ import {
stopDaemon,
writeStatus,
} from '../daemon/manager';
import { loadSettings, saveSettings } from '../settings';
import { loadSettings, normalizeUrl, saveSettings } from '../settings';
import { executeToolCall } from '../tools';
import { cleanupAllProcesses } from '../tools/shell';
import { log, setVerbose } from '../utils/logger';
@@ -174,7 +175,7 @@ function buildDaemonArgs(options: ConnectOptions): string[] {
async function runConnect(options: ConnectOptions, isDaemonChild: boolean) {
const auth = await resolveToken(options);
const settings = loadSettings();
const gatewayUrl = options.gateway?.replace(/\/$/, '') || settings?.gatewayUrl;
const gatewayUrl = normalizeUrl(options.gateway) || settings?.gatewayUrl;
if (!gatewayUrl && settings?.serverUrl) {
log.error(
@@ -194,7 +195,9 @@ async function runConnect(options: ConnectOptions, isDaemonChild: boolean) {
deviceId: options.deviceId,
gatewayUrl: resolvedGatewayUrl,
logger: isDaemonChild ? createDaemonLogger() : log,
serverUrl: auth.serverUrl,
token: auth.token,
tokenType: auth.tokenType,
userId: auth.userId,
});
@@ -214,7 +217,7 @@ async function runConnect(options: ConnectOptions, isDaemonChild: boolean) {
info(` Hostname : ${os.hostname()}`);
info(` Platform : ${process.platform}`);
info(` Gateway : ${resolvedGatewayUrl}`);
info(` Auth : jwt`);
info(` Auth : ${auth.tokenType}`);
info(` Mode : ${isDaemonChild ? 'daemon' : 'foreground'}`);
info('───────────────────');
@@ -285,13 +288,19 @@ async function runConnect(options: ConnectOptions, isDaemonChild: boolean) {
// Handle auth failed
client.on('auth_failed', (reason) => {
error(`Authentication failed: ${reason}`);
error("Run 'lh login' to re-authenticate.");
error(
`Run 'lh login', or set ${CLI_API_KEY_ENV} and run 'lh login --server <url>' to configure API key authentication.`,
);
cleanup();
process.exit(1);
});
// Handle auth expired
client.on('auth_expired', async () => {
if (auth.tokenType === 'apiKey') {
return;
}
error('Authentication expired. Attempting to refresh...');
const refreshed = await resolveToken({});
if (refreshed) {
+42 -1
View File
@@ -3,11 +3,15 @@ import fs from 'node:fs';
import { Command } from 'commander';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { getUserIdFromApiKey } from '../auth/apiKey';
import { saveCredentials } from '../auth/credentials';
import { loadSettings, saveSettings } from '../settings';
import { log } from '../utils/logger';
import { registerLoginCommand, resolveCommandExecutable } from './login';
vi.mock('../auth/apiKey', () => ({
getUserIdFromApiKey: vi.fn(),
}));
vi.mock('../auth/credentials', () => ({
saveCredentials: vi.fn(),
}));
@@ -37,6 +41,7 @@ vi.mock('node:child_process', () => ({
describe('login command', () => {
let exitSpy: ReturnType<typeof vi.spyOn>;
const originalApiKey = process.env.LOBEHUB_CLI_API_KEY;
const originalPath = process.env.PATH;
const originalPathext = process.env.PATHEXT;
const originalSystemRoot = process.env.SystemRoot;
@@ -46,11 +51,13 @@ describe('login command', () => {
vi.stubGlobal('fetch', vi.fn());
exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
vi.mocked(loadSettings).mockReturnValue(null);
delete process.env.LOBEHUB_CLI_API_KEY;
});
afterEach(() => {
vi.useRealTimers();
exitSpy.mockRestore();
process.env.LOBEHUB_CLI_API_KEY = originalApiKey;
process.env.PATH = originalPath;
process.env.PATHEXT = originalPathext;
process.env.SystemRoot = originalSystemRoot;
@@ -102,8 +109,12 @@ describe('login command', () => {
} as any;
}
async function runLogin(program: Command, args: string[] = []) {
return program.parseAsync(['node', 'test', 'login', ...args]);
}
async function runLoginAndAdvanceTimers(program: Command, args: string[] = []) {
const parsePromise = program.parseAsync(['node', 'test', 'login', ...args]);
const parsePromise = runLogin(program, args);
// Advance timers to let sleep resolve in the polling loop
for (let i = 0; i < 10; i++) {
await vi.advanceTimersByTimeAsync(2000);
@@ -130,6 +141,19 @@ describe('login command', () => {
expect(log.info).toHaveBeenCalledWith(expect.stringContaining('Login successful'));
});
it('should use environment api key without storing credentials', async () => {
process.env.LOBEHUB_CLI_API_KEY = 'sk-lh-env-test';
vi.mocked(getUserIdFromApiKey).mockResolvedValue('user-123');
const program = createProgram();
await runLogin(program);
expect(getUserIdFromApiKey).toHaveBeenCalledWith('sk-lh-env-test', 'https://app.lobehub.com');
expect(saveCredentials).not.toHaveBeenCalled();
expect(saveSettings).toHaveBeenCalledWith({ serverUrl: 'https://app.lobehub.com' });
expect(log.info).toHaveBeenCalledWith(expect.stringContaining('Login successful'));
});
it('should persist custom server into settings', async () => {
vi.mocked(fetch)
.mockResolvedValueOnce(deviceAuthResponse())
@@ -159,6 +183,23 @@ describe('login command', () => {
});
});
it('should preserve existing gateway for environment api key on the same server', async () => {
process.env.LOBEHUB_CLI_API_KEY = 'sk-lh-env-test';
vi.mocked(getUserIdFromApiKey).mockResolvedValue('user-123');
vi.mocked(loadSettings).mockReturnValueOnce({
gatewayUrl: 'https://gateway.example.com',
serverUrl: 'https://test.com',
});
const program = createProgram();
await runLogin(program, ['--server', 'https://test.com/']);
expect(saveSettings).toHaveBeenCalledWith({
gatewayUrl: 'https://gateway.example.com',
serverUrl: 'https://test.com',
});
});
it('should clear existing gateway when logging into a different server', async () => {
vi.mocked(loadSettings).mockReturnValueOnce({
gatewayUrl: 'https://gateway.example.com',
+36 -3
View File
@@ -4,9 +4,11 @@ import path from 'node:path';
import type { Command } from 'commander';
import { getUserIdFromApiKey } from '../auth/apiKey';
import { saveCredentials } from '../auth/credentials';
import { CLI_API_KEY_ENV } from '../constants/auth';
import { OFFICIAL_SERVER_URL } from '../constants/urls';
import { loadSettings, saveSettings } from '../settings';
import { loadSettings, normalizeUrl, saveSettings } from '../settings';
import { log } from '../utils/logger';
const CLIENT_ID = 'lobehub-cli';
@@ -51,13 +53,43 @@ async function parseJsonResponse<T>(res: Response, endpoint: string): Promise<T>
export function registerLoginCommand(program: Command) {
program
.command('login')
.description('Log in to LobeHub via browser (Device Code Flow)')
.description('Log in to LobeHub via browser (Device Code Flow) or configure API key server')
.option('--server <url>', 'LobeHub server URL', OFFICIAL_SERVER_URL)
.action(async (options: LoginOptions) => {
const serverUrl = options.server.replace(/\/$/, '');
const serverUrl = normalizeUrl(options.server) || OFFICIAL_SERVER_URL;
log.info('Starting login...');
const apiKey = process.env[CLI_API_KEY_ENV];
if (apiKey) {
try {
await getUserIdFromApiKey(apiKey, serverUrl);
const existingSettings = loadSettings();
const shouldPreserveGateway = existingSettings?.serverUrl === serverUrl;
saveSettings(
shouldPreserveGateway
? {
gatewayUrl: existingSettings.gatewayUrl,
serverUrl,
}
: {
// Gateway auth is tied to the login server's token issuer/JWKS.
// When server changes, clear old gateway to avoid stale cross-environment config.
serverUrl,
},
);
log.info('Login successful! Credentials saved.');
return;
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
log.error(`API key validation failed: ${message}`);
process.exit(1);
return;
}
}
// Step 1: Request device code
let deviceAuth: DeviceAuthResponse;
try {
@@ -164,6 +196,7 @@ export function registerLoginCommand(program: Command) {
: undefined,
refreshToken: body.refresh_token,
});
const existingSettings = loadSettings();
const shouldPreserveGateway = existingSettings?.serverUrl === serverUrl;
+85
View File
@@ -0,0 +1,85 @@
import { Command } from 'commander';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { registerManCommand } from './man';
describe('man command', () => {
let consoleSpy: ReturnType<typeof vi.spyOn>;
beforeEach(() => {
consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
});
afterEach(() => {
consoleSpy.mockRestore();
});
function createProgram() {
const program = new Command();
program.name('lh').description('Sample CLI').version('1.0.0');
const generate = program
.command('generate')
.alias('gen')
.description('Generate content')
.option('-m, --model <model>', 'Model to use');
generate
.command('text <prompt>')
.description('Generate text from a prompt')
.option('--json', 'Output raw JSON');
program.command('login').description('Log in to LobeHub');
registerManCommand(program);
program.exitOverride();
return program;
}
it('renders a manual page for the root command', async () => {
const program = createProgram();
await program.parseAsync(['node', 'test', 'man']);
const output = consoleSpy.mock.calls.at(0)?.[0];
expect(output).toContain('LH(1)');
expect(output).toContain('NAME\n lh - Sample CLI');
expect(output).toContain('ALIASES\n lobe, lobehub');
expect(output).toContain('SYNOPSIS\n lh [options] [command]');
expect(output).toContain('generate|gen [options] [command]');
expect(output).toContain('man [options] [command...]');
});
it('renders a manual page for a command with subcommands', async () => {
const program = createProgram();
await program.parseAsync(['node', 'test', 'man', 'generate']);
const output = consoleSpy.mock.calls.at(0)?.[0];
expect(output).toContain('LH-GENERATE(1)');
expect(output).toContain('NAME\n lh generate - Generate content');
expect(output).toContain('ALIASES\n gen');
expect(output).toContain('SYNOPSIS\n lh generate [options] [command]');
expect(output).toContain('text [options] <prompt>');
expect(output).toContain('-m, --model <model>');
});
it('renders arguments for a leaf command', async () => {
const program = createProgram();
await program.parseAsync(['node', 'test', 'man', 'generate', 'text']);
const output = consoleSpy.mock.calls.at(0)?.[0];
expect(output).toContain('LH-GENERATE-TEXT(1)');
expect(output).toContain('NAME\n lh generate text - Generate text from a prompt');
expect(output).toContain('ARGUMENTS');
expect(output).toContain('<prompt>');
expect(output).toContain('Required argument');
expect(output).toContain('SEE ALSO');
});
});
+212
View File
@@ -0,0 +1,212 @@
import type { Argument, Command } from 'commander';
const ROOT_ALIASES = ['lobe', 'lobehub'];
const HELP_COMMAND_NAME = 'help';
interface DefinitionItem {
description: string;
term: string;
}
interface ResolutionResult {
command?: Command;
error?: string;
}
export function registerManCommand(program: Command) {
program
.command('man [command...]')
.description('Show a manual page for the CLI or a subcommand')
.action((commandPath: string[] | undefined) => {
const segments = commandPath ?? [];
const resolution = resolveCommandPath(program, segments);
if (!resolution.command) {
program.error(resolution.error || 'Unknown command path.');
return;
}
console.log(renderManualPage(program, resolution.command));
});
}
function resolveCommandPath(root: Command, segments: string[]): ResolutionResult {
let current = root;
for (const segment of segments) {
const next = getVisibleCommands(current).find(
(command) => command.name() === segment || command.aliases().includes(segment),
);
if (!next) {
const currentPath = buildCommandPath(current).join(' ');
const available = getVisibleCommands(current)
.map((command) => command.name())
.join(', ');
return {
error: `Unknown command "${segment}" under "${currentPath}". Available: ${available || 'none'}.`,
};
}
current = next;
}
return { command: current };
}
function renderManualPage(root: Command, command: Command) {
const sections = [
formatManualHeader(command),
formatNameSection(command),
formatSynopsisSection(root, command),
formatAliasesSection(command),
formatDescriptionSection(command),
formatArgumentsSection(command),
formatCommandsSection(command),
formatOptionsSection(command),
formatSeeAlsoSection(root, command),
].filter(Boolean);
return sections.join('\n\n');
}
function formatManualHeader(command: Command) {
return `${buildCommandPath(command).join('-').toUpperCase()}(1)`;
}
function formatNameSection(command: Command) {
return ['NAME', ` ${buildCommandPath(command).join(' ')} - ${command.description()}`].join('\n');
}
function formatSynopsisSection(root: Command, command: Command) {
return ['SYNOPSIS', ` ${buildSynopsis(root, command)}`].join('\n');
}
function formatAliasesSection(command: Command) {
const aliases = command.parent ? command.aliases() : ROOT_ALIASES;
if (aliases.length === 0) return '';
return ['ALIASES', ` ${aliases.join(', ')}`].join('\n');
}
function formatDescriptionSection(command: Command) {
const description = command.description() || 'No description available.';
return ['DESCRIPTION', ` ${description}`].join('\n');
}
function formatArgumentsSection(command: Command) {
if (command.registeredArguments.length === 0) return '';
const items = command.registeredArguments.map((argument) => ({
description: describeArgument(argument),
term: formatArgumentTerm(argument),
}));
return ['ARGUMENTS', ...formatDefinitionList(items)].join('\n');
}
function formatCommandsSection(command: Command) {
const help = command.createHelp();
const items = getVisibleCommands(command).map((subcommand) => ({
description: help.subcommandDescription(subcommand),
term: buildSubcommandTerm(subcommand),
}));
if (items.length === 0) return '';
return ['COMMANDS', ...formatDefinitionList(items)].join('\n');
}
function formatOptionsSection(command: Command) {
const help = command.createHelp();
const items = help.visibleOptions(command).map((option) => ({
description: help.optionDescription(option),
term: help.optionTerm(option),
}));
if (items.length === 0) return '';
return ['OPTIONS', ...formatDefinitionList(items)].join('\n');
}
function formatSeeAlsoSection(root: Command, command: Command) {
const items = new Set<string>();
const currentPath = buildCommandPath(command);
items.add(`${currentPath.join(' ')} --help`);
const parent = command.parent;
if (parent) {
const parentPath = buildCommandPath(parent).slice(1).join(' ');
items.add(parentPath ? `lh man ${parentPath}` : 'lh man');
}
for (const subcommand of getVisibleCommands(command).slice(0, 5)) {
items.add(`lh man ${buildCommandPath(subcommand).slice(1).join(' ')}`);
}
return ['SEE ALSO', ...Array.from(items).map((item) => ` ${item}`)].join('\n');
}
function getVisibleCommands(command: Command) {
const help = command.createHelp();
return help
.visibleCommands(command)
.filter((subcommand) => subcommand.name() !== HELP_COMMAND_NAME);
}
function buildSynopsis(root: Command, command: Command) {
const path = buildCommandPath(command);
if (command === root) {
return `${path[0]} ${command.usage()}`.trim();
}
return `${path.join(' ')} ${command.usage()}`.trim();
}
function buildCommandPath(command: Command): string[] {
const path: string[] = [];
let current: Command | null = command;
while (current) {
path.unshift(current.name());
current = current.parent || null;
}
return path;
}
function buildSubcommandTerm(command: Command) {
const name = [command.name(), ...command.aliases()].join('|');
const usage = command.usage();
return usage ? `${name} ${usage}` : name;
}
function formatDefinitionList(items: DefinitionItem[]) {
const width = Math.max(...items.map((item) => item.term.length));
return items.map((item) => ` ${item.term.padEnd(width)} ${item.description}`);
}
function formatArgumentTerm(argument: Argument) {
const name = argument.name();
if (argument.required) {
return argument.variadic ? `<${name}...>` : `<${name}>`;
}
return argument.variadic ? `[${name}...]` : `[${name}]`;
}
function describeArgument(argument: Argument) {
const required = argument.required ? 'Required' : 'Optional';
const variadic = argument.variadic ? 'variadic ' : '';
return `${required} ${variadic}argument`;
}
+17 -1
View File
@@ -3,10 +3,16 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
// Mock resolveToken
vi.mock('../auth/resolveToken', () => ({
resolveToken: vi.fn().mockResolvedValue({ token: 'test-token', userId: 'test-user' }),
resolveToken: vi.fn().mockResolvedValue({
serverUrl: 'https://app.lobehub.com',
token: 'test-token',
tokenType: 'jwt',
userId: 'test-user',
}),
}));
vi.mock('../settings', () => ({
loadSettings: vi.fn().mockReturnValue(null),
normalizeUrl: vi.fn((url?: string) => (url ? url.replace(/\/$/, '') : undefined)),
saveSettings: vi.fn(),
}));
@@ -115,6 +121,16 @@ describe('status command', () => {
serverUrl: 'https://self-hosted.example.com',
});
});
it('should pass the resolved serverUrl to GatewayClient', async () => {
const program = createProgram();
const parsePromise = program.parseAsync(['node', 'test', 'status']);
await vi.advanceTimersByTimeAsync(0);
clientEventHandlers['connected']?.();
await parsePromise;
expect(clientOptions.serverUrl).toBe('https://app.lobehub.com');
});
it('should log CONNECTED on successful connection', async () => {
const program = createProgram();
+4 -2
View File
@@ -3,7 +3,7 @@ import type { Command } from 'commander';
import { resolveToken } from '../auth/resolveToken';
import { OFFICIAL_GATEWAY_URL } from '../constants/urls';
import { loadSettings, saveSettings } from '../settings';
import { loadSettings, normalizeUrl, saveSettings } from '../settings';
import { log, setVerbose } from '../utils/logger';
interface StatusOptions {
@@ -30,7 +30,7 @@ export function registerStatusCommand(program: Command) {
const auth = await resolveToken(options);
const settings = loadSettings();
const gatewayUrl = options.gateway?.replace(/\/$/, '') || settings?.gatewayUrl;
const gatewayUrl = normalizeUrl(options.gateway) || settings?.gatewayUrl;
if (!gatewayUrl && settings?.serverUrl) {
log.error(
@@ -50,7 +50,9 @@ export function registerStatusCommand(program: Command) {
autoReconnect: false,
gatewayUrl: gatewayUrl || OFFICIAL_GATEWAY_URL,
logger: log,
serverUrl: auth.serverUrl,
token: auth.token,
tokenType: auth.tokenType,
userId: auth.userId,
});
+95
View File
@@ -0,0 +1,95 @@
import type { Command } from 'commander';
import pc from 'picocolors';
import { getTrpcClient } from '../../api/client';
import { log } from '../../utils/logger';
export function registerCheckpointCommands(task: Command) {
// ── checkpoint ──────────────────────────────────────────────
const cp = task.command('checkpoint').description('Manage task checkpoints');
cp.command('view <id>')
.description('View checkpoint config for a task')
.action(async (id: string) => {
const client = await getTrpcClient();
const result = await client.task.getCheckpoint.query({ id });
const c = result.data as any;
console.log(`\n${pc.bold('Checkpoint config:')}`);
console.log(` onAgentRequest: ${c.onAgentRequest ?? pc.dim('not set (default: true)')}`);
if (c.topic) {
console.log(` topic.before: ${c.topic.before ?? false}`);
console.log(` topic.after: ${c.topic.after ?? false}`);
}
if (c.tasks?.beforeIds?.length > 0) {
console.log(` tasks.beforeIds: ${c.tasks.beforeIds.join(', ')}`);
}
if (c.tasks?.afterIds?.length > 0) {
console.log(` tasks.afterIds: ${c.tasks.afterIds.join(', ')}`);
}
if (
!c.topic &&
!c.tasks?.beforeIds?.length &&
!c.tasks?.afterIds?.length &&
c.onAgentRequest === undefined
) {
console.log(` ${pc.dim('(no checkpoints configured)')}`);
}
console.log();
});
cp.command('set <id>')
.description('Configure checkpoints')
.option('--on-agent-request <bool>', 'Allow agent to request review (true/false)')
.option('--topic-before <bool>', 'Pause before each topic (true/false)')
.option('--topic-after <bool>', 'Pause after each topic (true/false)')
.option('--before <ids>', 'Pause before these subtask identifiers (comma-separated)')
.option('--after <ids>', 'Pause after these subtask identifiers (comma-separated)')
.action(
async (
id: string,
options: {
after?: string;
before?: string;
onAgentRequest?: string;
topicAfter?: string;
topicBefore?: string;
},
) => {
const client = await getTrpcClient();
// Get current config first
const current = (await client.task.getCheckpoint.query({ id })).data as any;
const checkpoint: any = { ...current };
if (options.onAgentRequest !== undefined) {
checkpoint.onAgentRequest = options.onAgentRequest === 'true';
}
if (options.topicBefore !== undefined || options.topicAfter !== undefined) {
checkpoint.topic = { ...checkpoint.topic };
if (options.topicBefore !== undefined)
checkpoint.topic.before = options.topicBefore === 'true';
if (options.topicAfter !== undefined)
checkpoint.topic.after = options.topicAfter === 'true';
}
if (options.before !== undefined) {
checkpoint.tasks = { ...checkpoint.tasks };
checkpoint.tasks.beforeIds = options.before
.split(',')
.map((s: string) => s.trim())
.filter(Boolean);
}
if (options.after !== undefined) {
checkpoint.tasks = { ...checkpoint.tasks };
checkpoint.tasks.afterIds = options.after
.split(',')
.map((s: string) => s.trim())
.filter(Boolean);
}
await client.task.updateCheckpoint.mutate({ checkpoint, id });
log.info('Checkpoint updated.');
},
);
}
+56
View File
@@ -0,0 +1,56 @@
import type { Command } from 'commander';
import { getTrpcClient } from '../../api/client';
import { outputJson, printTable, timeAgo } from '../../utils/format';
import { log } from '../../utils/logger';
export function registerDepCommands(task: Command) {
// ── dep ──────────────────────────────────────────────
const dep = task.command('dep').description('Manage task dependencies');
dep
.command('add <taskId> <dependsOnId>')
.description('Add dependency (taskId blocks on dependsOnId)')
.option('--type <type>', 'Dependency type (blocks/relates)', 'blocks')
.action(async (taskId: string, dependsOnId: string, options: { type?: string }) => {
const client = await getTrpcClient();
await client.task.addDependency.mutate({
dependsOnId,
taskId,
type: (options.type || 'blocks') as any,
});
log.info(`Dependency added: ${taskId} ${options.type || 'blocks'} on ${dependsOnId}`);
});
dep
.command('rm <taskId> <dependsOnId>')
.description('Remove dependency')
.action(async (taskId: string, dependsOnId: string) => {
const client = await getTrpcClient();
await client.task.removeDependency.mutate({ dependsOnId, taskId });
log.info(`Dependency removed.`);
});
dep
.command('list <taskId>')
.description('List dependencies for a task')
.option('--json [fields]', 'Output JSON')
.action(async (taskId: string, options: { json?: string | boolean }) => {
const client = await getTrpcClient();
const result = await client.task.getDependencies.query({ id: taskId });
if (options.json !== undefined) {
outputJson(result.data, options.json);
return;
}
if (!result.data || result.data.length === 0) {
log.info('No dependencies.');
return;
}
const rows = result.data.map((d: any) => [d.type, d.dependsOnId, timeAgo(d.createdAt)]);
printTable(rows, ['TYPE', 'DEPENDS ON', 'CREATED']);
});
}
+102
View File
@@ -0,0 +1,102 @@
import type { Command } from 'commander';
import pc from 'picocolors';
import { getTrpcClient } from '../../api/client';
import { log } from '../../utils/logger';
export function registerDocCommands(task: Command) {
// ── doc ──────────────────────────────────────────────
const dc = task.command('doc').description('Manage task workspace documents');
dc.command('create <id>')
.description('Create a document and pin it to the task')
.requiredOption('-t, --title <title>', 'Document title')
.option('-b, --body <content>', 'Document content')
.option('--parent <docId>', 'Parent document/folder ID')
.option('--folder', 'Create as folder')
.action(
async (
id: string,
options: { body?: string; folder?: boolean; parent?: string; title: string },
) => {
const client = await getTrpcClient();
// Create document
const fileType = options.folder ? 'custom/folder' : undefined;
const content = options.body || '';
const result = await client.document.createDocument.mutate({
content,
editorData: options.folder ? undefined : JSON.stringify({ content, type: 'doc' }),
fileType,
parentId: options.parent,
title: options.title,
});
// Pin to task
await client.task.pinDocument.mutate({
documentId: result.id,
pinnedBy: 'user',
taskId: id,
});
const icon = options.folder ? '📁' : '📄';
log.info(`${icon} Created & pinned: ${pc.bold(options.title)} ${pc.dim(result.id)}`);
},
);
dc.command('pin <id> <documentId>')
.description('Pin an existing document to a task')
.action(async (id: string, documentId: string) => {
const client = await getTrpcClient();
await client.task.pinDocument.mutate({ documentId, pinnedBy: 'user', taskId: id });
log.info(`Pinned ${pc.dim(documentId)} to ${pc.bold(id)}.`);
});
dc.command('unpin <id> <documentId>')
.description('Unpin a document from a task')
.action(async (id: string, documentId: string) => {
const client = await getTrpcClient();
await client.task.unpinDocument.mutate({ documentId, taskId: id });
log.info(`Unpinned ${pc.dim(documentId)} from ${pc.bold(id)}.`);
});
dc.command('mv <id> <documentId> <folder>')
.description('Move a document into a folder (auto-creates folder if not found)')
.action(async (id: string, documentId: string, folder: string) => {
const client = await getTrpcClient();
// Check if folder is a document ID or a folder name
let folderId = folder;
if (!folder.startsWith('docs_')) {
// folder is a name, find or create it
const detail = await client.task.detail.query({ id });
const folders = detail.data.workspace || [];
// Search for existing folder by name
const existingFolder = folders.find((f) => f.title === folder);
if (existingFolder) {
folderId = existingFolder.documentId;
} else {
// Create folder and pin to task
const result = await client.document.createDocument.mutate({
content: '',
fileType: 'custom/folder',
title: folder,
});
await client.task.pinDocument.mutate({
documentId: result.id,
pinnedBy: 'user',
taskId: id,
});
folderId = result.id;
log.info(`📁 Created folder: ${pc.bold(folder)} ${pc.dim(folderId)}`);
}
}
// Move document into folder
await client.document.updateDocument.mutate({ id: documentId, parentId: folderId });
log.info(`Moved ${pc.dim(documentId)} → 📁 ${pc.bold(folder)}`);
});
}
+74
View File
@@ -0,0 +1,74 @@
import pc from 'picocolors';
export function statusBadge(status: string): string {
const pad = (s: string) => s.padEnd(9);
switch (status) {
case 'backlog': {
return pc.dim(`${pad('backlog')}`);
}
case 'blocked': {
return pc.red(`${pad('blocked')}`);
}
case 'running': {
return pc.blue(`${pad('running')}`);
}
case 'paused': {
return pc.yellow(`${pad('paused')}`);
}
case 'completed': {
return pc.green(`${pad('completed')}`);
}
case 'failed': {
return pc.red(`${pad('failed')}`);
}
case 'timeout': {
return pc.red(`${pad('timeout')}`);
}
case 'canceled': {
return pc.dim(`${pad('canceled')}`);
}
default: {
return status;
}
}
}
export function briefIcon(type: string): string {
switch (type) {
case 'decision': {
return '📋';
}
case 'result': {
return '✅';
}
case 'insight': {
return '💡';
}
case 'error': {
return '❌';
}
default: {
return '📌';
}
}
}
export function priorityLabel(priority: number | null | undefined): string {
switch (priority) {
case 1: {
return pc.red('urgent');
}
case 2: {
return pc.yellow('high');
}
case 3: {
return 'normal';
}
case 4: {
return pc.dim('low');
}
default: {
return pc.dim('-');
}
}
}
+624
View File
@@ -0,0 +1,624 @@
import type { Command } from 'commander';
import pc from 'picocolors';
import { getTrpcClient } from '../../api/client';
import {
confirm,
displayWidth,
outputJson,
printTable,
timeAgo,
truncate,
} from '../../utils/format';
import { log } from '../../utils/logger';
import { registerCheckpointCommands } from './checkpoint';
import { registerDepCommands } from './dep';
import { registerDocCommands } from './doc';
import { briefIcon, priorityLabel, statusBadge } from './helpers';
import { registerLifecycleCommands } from './lifecycle';
import { registerReviewCommands } from './review';
import { registerTopicCommands } from './topic';
export function registerTaskCommand(program: Command) {
const task = program.command('task').description('Manage agent tasks');
// ── list ──────────────────────────────────────────────
task
.command('list')
.description('List tasks')
.option(
'--status <status>',
'Filter by status (pending/running/paused/completed/failed/canceled)',
)
.option('--root', 'Only show root tasks (no parent)')
.option('--parent <id>', 'Filter by parent task ID')
.option('--agent <id>', 'Filter by assignee agent ID')
.option('-L, --limit <n>', 'Page size', '50')
.option('--offset <n>', 'Offset', '0')
.option('--tree', 'Display as tree structure')
.option('--json [fields]', 'Output JSON')
.action(
async (options: {
agent?: string;
json?: string | boolean;
limit?: string;
offset?: string;
parent?: string;
root?: boolean;
status?: string;
tree?: boolean;
}) => {
const client = await getTrpcClient();
const input: Record<string, any> = {};
if (options.status) input.status = options.status;
if (options.root) input.parentTaskId = null;
if (options.parent) input.parentTaskId = options.parent;
if (options.agent) input.assigneeAgentId = options.agent;
if (options.limit) input.limit = Number.parseInt(options.limit, 10);
if (options.offset) input.offset = Number.parseInt(options.offset, 10);
// For tree mode, fetch all tasks (no pagination limit)
if (options.tree) {
input.limit = 100;
delete input.offset;
}
const result = await client.task.list.query(input as any);
if (options.json !== undefined) {
outputJson(result.data, options.json);
return;
}
if (!result.data || result.data.length === 0) {
log.info('No tasks found.');
return;
}
if (options.tree) {
// Build tree display
const taskMap = new Map<string, any>();
for (const t of result.data) taskMap.set(t.id, t);
const roots = result.data.filter((t: any) => !t.parentTaskId);
const children = new Map<string, any[]>();
for (const t of result.data) {
if (t.parentTaskId) {
const list = children.get(t.parentTaskId) || [];
list.push(t);
children.set(t.parentTaskId, list);
}
}
// Sort children by sortOrder first, then seq
for (const [, list] of children) {
list.sort(
(a: any, b: any) =>
(a.sortOrder ?? 0) - (b.sortOrder ?? 0) || (a.seq ?? 0) - (b.seq ?? 0),
);
}
const printNode = (t: any, prefix: string, isLast: boolean, isRoot: boolean) => {
const connector = isRoot ? '' : isLast ? '└── ' : '├── ';
const name = truncate(t.name || t.instruction, 40);
console.log(
`${prefix}${connector}${pc.dim(t.identifier)} ${statusBadge(t.status)} ${name}`,
);
const childList = children.get(t.id) || [];
const newPrefix = isRoot ? '' : prefix + (isLast ? ' ' : '│ ');
childList.forEach((child: any, i: number) => {
printNode(child, newPrefix, i === childList.length - 1, false);
});
};
for (const root of roots) {
printNode(root, '', true, true);
}
log.info(`Total: ${result.total}`);
return;
}
const rows = result.data.map((t: any) => [
pc.dim(t.identifier),
truncate(t.name || t.instruction, 40),
statusBadge(t.status),
priorityLabel(t.priority),
t.assigneeAgentId ? pc.dim(t.assigneeAgentId) : '-',
t.parentTaskId ? pc.dim('↳ subtask') : '',
timeAgo(t.createdAt),
]);
printTable(rows, ['ID', 'NAME', 'STATUS', 'PRI', 'AGENT', 'TYPE', 'CREATED']);
log.info(`Total: ${result.total}`);
},
);
// ── view ──────────────────────────────────────────────
task
.command('view <id>')
.description('View task details (by ID or identifier like T-1)')
.option('--json [fields]', 'Output JSON')
.action(async (id: string, options: { json?: string | boolean }) => {
const client = await getTrpcClient();
// ── Auto-detect by id prefix ──
// docs_ → show document content
if (id.startsWith('docs_')) {
const doc = await client.document.getDocumentDetail.query({ id });
if (options.json !== undefined) {
outputJson(doc, options.json);
return;
}
if (!doc) {
log.error('Document not found.');
return;
}
console.log(`\n📄 ${pc.bold(doc.title || 'Untitled')} ${pc.dim(doc.id)}`);
if (doc.fileType) console.log(`${pc.dim('Type:')} ${doc.fileType}`);
if (doc.totalCharCount) console.log(`${pc.dim('Size:')} ${doc.totalCharCount} chars`);
console.log(`${pc.dim('Updated:')} ${timeAgo(doc.updatedAt)}`);
console.log();
if (doc.content) {
console.log(doc.content);
}
return;
}
// tpc_ → show topic messages
if (id.startsWith('tpc_')) {
const messages = await client.message.getMessages.query({ topicId: id });
const items = Array.isArray(messages) ? messages : [];
if (options.json !== undefined) {
outputJson(items, options.json);
return;
}
if (items.length === 0) {
log.info('No messages in this topic.');
return;
}
console.log();
for (const msg of items) {
const role =
msg.role === 'assistant'
? pc.green('Assistant')
: msg.role === 'user'
? pc.blue('User')
: pc.dim(msg.role);
console.log(`${pc.bold(role)} ${pc.dim(timeAgo(msg.createdAt))}`);
if (msg.content) {
console.log(msg.content);
}
console.log();
}
return;
}
// Default: task detail
const result = await client.task.detail.query({ id });
if (options.json !== undefined) {
outputJson(result.data, options.json);
return;
}
const t = result.data;
// ── Header ──
console.log(`\n${pc.bold(t.identifier)} ${t.name || ''}`);
console.log(
`${pc.dim('Status:')} ${statusBadge(t.status)} ${pc.dim('Priority:')} ${priorityLabel(t.priority)}`,
);
console.log(`${pc.dim('Instruction:')} ${t.instruction}`);
if (t.description) console.log(`${pc.dim('Description:')} ${t.description}`);
if (t.agentId) console.log(`${pc.dim('Agent:')} ${t.agentId}`);
if (t.userId) console.log(`${pc.dim('User:')} ${t.userId}`);
if (t.parent) {
console.log(`${pc.dim('Parent:')} ${t.parent.identifier} ${t.parent.name || ''}`);
}
const topicInfo = t.topicCount ? `${t.topicCount}` : '0';
const createdInfo = t.createdAt ? timeAgo(t.createdAt) : '-';
console.log(`${pc.dim('Topics:')} ${topicInfo} ${pc.dim('Created:')} ${createdInfo}`);
if (t.heartbeat?.timeout && t.heartbeat.lastAt) {
const hb = timeAgo(t.heartbeat.lastAt);
const interval = t.heartbeat.interval ? `${t.heartbeat.interval}s` : '-';
const elapsed = (Date.now() - new Date(t.heartbeat.lastAt).getTime()) / 1000;
const isStuck = t.status === 'running' && elapsed > t.heartbeat.timeout;
console.log(
`${pc.dim('Heartbeat:')} ${isStuck ? pc.red(hb) : hb} ${pc.dim('interval:')} ${interval} ${pc.dim('timeout:')} ${t.heartbeat.timeout}s${isStuck ? pc.red(' ⚠ TIMEOUT') : ''}`,
);
}
if (t.error) console.log(`${pc.red('Error:')} ${t.error}`);
// ── Subtasks ──
if (t.subtasks && t.subtasks.length > 0) {
// Build lookup: which subtasks are completed
const completedIdentifiers = new Set(
t.subtasks.filter((s) => s.status === 'completed').map((s) => s.identifier),
);
console.log(`\n${pc.bold('Subtasks:')}`);
for (const s of t.subtasks) {
const depInfo = s.blockedBy ? pc.dim(` ← blocks: ${s.blockedBy}`) : '';
// Show 'blocked' instead of 'backlog' if task has unresolved dependencies
const isBlocked = s.blockedBy && !completedIdentifiers.has(s.blockedBy);
const displayStatus = s.status === 'backlog' && isBlocked ? 'blocked' : s.status;
console.log(
` ${pc.dim(s.identifier)} ${statusBadge(displayStatus)} ${s.name || '(unnamed)'}${depInfo}`,
);
}
}
// ── Dependencies ──
if (t.dependencies && t.dependencies.length > 0) {
console.log(`\n${pc.bold('Dependencies:')}`);
for (const d of t.dependencies) {
const depName = d.name ? ` ${d.name}` : '';
console.log(` ${pc.dim(d.type || 'blocks')}: ${d.dependsOn}${depName}`);
}
}
// ── Checkpoint ──
{
const cp = t.checkpoint || {};
console.log(`\n${pc.bold('Checkpoint:')}`);
const hasConfig =
cp.onAgentRequest !== undefined ||
cp.topic?.before ||
cp.topic?.after ||
cp.tasks?.beforeIds?.length ||
cp.tasks?.afterIds?.length;
if (hasConfig) {
if (cp.onAgentRequest !== undefined)
console.log(` onAgentRequest: ${cp.onAgentRequest}`);
if (cp.topic?.before) console.log(` topic.before: ${cp.topic.before}`);
if (cp.topic?.after) console.log(` topic.after: ${cp.topic.after}`);
if (cp.tasks?.beforeIds?.length)
console.log(` tasks.before: ${cp.tasks.beforeIds.join(', ')}`);
if (cp.tasks?.afterIds?.length)
console.log(` tasks.after: ${cp.tasks.afterIds.join(', ')}`);
} else {
console.log(` ${pc.dim('(not configured, default: onAgentRequest=true)')}`);
}
}
// ── Review ──
{
const rv = t.review as any;
console.log(`\n${pc.bold('Review:')}`);
if (rv && rv.enabled) {
console.log(
` judge: ${rv.judge?.model || 'default'}${rv.judge?.provider ? ` (${rv.judge.provider})` : ''}`,
);
console.log(` maxIterations: ${rv.maxIterations} autoRetry: ${rv.autoRetry}`);
if (rv.rubrics?.length > 0) {
for (let i = 0; i < rv.rubrics.length; i++) {
const rb = rv.rubrics[i];
const threshold = rb.threshold ? `${Math.round(rb.threshold * 100)}%` : '';
const typeTag = pc.dim(`[${rb.type}]`);
let configInfo = '';
if (rb.type === 'llm-rubric') configInfo = rb.config?.criteria || '';
else if (rb.type === 'contains' || rb.type === 'equals')
configInfo = `value="${rb.config?.value}"`;
else if (rb.type === 'regex') configInfo = `pattern="${rb.config?.pattern}"`;
console.log(` ${i + 1}. ${rb.name} ${typeTag}${threshold} ${pc.dim(configInfo)}`);
}
}
} else {
console.log(` ${pc.dim('(not configured)')}`);
}
}
// ── Workspace ──
{
const nodes = t.workspace || [];
if (nodes.length === 0) {
console.log(`\n${pc.bold('Workspace:')}`);
console.log(` ${pc.dim('No documents yet.')}`);
} else {
const countNodes = (list: typeof nodes): number =>
list.reduce((sum, n) => sum + 1 + (n.children ? countNodes(n.children) : 0), 0);
console.log(`\n${pc.bold(`Workspace (${countNodes(nodes)}):`)}`);
const formatSize = (chars: number | null | undefined) => {
if (!chars) return '';
if (chars >= 10_000) return `${(chars / 1000).toFixed(1)}k`;
return `${chars}`;
};
const LEFT_COL = 56;
const FROM_WIDTH = 10;
const renderNodes = (list: typeof nodes, indent: string, isChild: boolean) => {
for (let i = 0; i < list.length; i++) {
const node = list[i];
const isFolder = node.fileType === 'custom/folder';
const isLast = i === list.length - 1;
const icon = isFolder ? '📁' : '📄';
const connector = isChild ? (isLast ? '└── ' : '├── ') : '';
const prefix = `${indent}${connector}${icon} `;
const titleStr = truncate(node.title || 'Untitled', LEFT_COL - displayWidth(prefix));
const titlePad = ' '.repeat(
Math.max(1, LEFT_COL - displayWidth(prefix) - displayWidth(titleStr)),
);
const fromStr = node.sourceTaskIdentifier ? `${node.sourceTaskIdentifier}` : '';
const fromPad = ' '.repeat(Math.max(1, FROM_WIDTH - fromStr.length + 1));
const size =
!isFolder && node.size
? formatSize(node.size).padStart(6) + ' chars'
: ''.padStart(12);
const ago = node.createdAt ? ` ${timeAgo(node.createdAt)}` : '';
console.log(
`${prefix}${titleStr}${titlePad}${pc.dim(`(${node.documentId})`)} ${fromStr}${fromPad}${pc.dim(size)}${pc.dim(ago)}`,
);
if (node.children && node.children.length > 0) {
const childIndent = isChild ? indent + (isLast ? ' ' : '│ ') : indent;
renderNodes(node.children, childIndent, true);
}
}
};
renderNodes(nodes, ' ', false);
}
}
// ── Activities (already sorted desc by service) ──
{
console.log(`\n${pc.bold('Activities:')}`);
const acts = t.activities || [];
if (acts.length === 0) {
console.log(` ${pc.dim('No activities yet.')}`);
} else {
for (const act of acts) {
const ago = act.time ? timeAgo(act.time) : '';
const idSuffix = act.id ? ` ${pc.dim(act.id)}` : '';
if (act.type === 'topic') {
const sBadge = statusBadge(act.status || 'running');
console.log(
` 💬 ${pc.dim(ago.padStart(7))} Topic #${act.seq || '?'} ${act.title || 'Untitled'} ${sBadge}${idSuffix}`,
);
} else if (act.type === 'brief') {
const icon = briefIcon(act.briefType || '');
const pri =
act.priority === 'urgent'
? pc.red(' [urgent]')
: act.priority === 'normal'
? pc.yellow(' [normal]')
: '';
const resolved = act.resolvedAction ? pc.green(` ✏️ ${act.resolvedAction}`) : '';
const typeLabel = pc.dim(`[${act.briefType}]`);
console.log(
` ${icon} ${pc.dim(ago.padStart(7))} Brief ${typeLabel} ${act.title}${pri}${resolved}${idSuffix}`,
);
} else if (act.type === 'comment') {
const author = act.agentId ? `🤖 ${act.agentId}` : '👤 user';
console.log(` 💭 ${pc.dim(ago.padStart(7))} ${pc.cyan(author)} ${act.content}`);
}
}
}
}
console.log();
});
// ── create ──────────────────────────────────────────────
task
.command('create')
.description('Create a new task')
.requiredOption('-i, --instruction <text>', 'Task instruction')
.option('-n, --name <name>', 'Task name')
.option('--agent <id>', 'Assign to agent')
.option('--parent <id>', 'Parent task ID')
.option('--priority <n>', 'Priority (0=none, 1=urgent, 2=high, 3=normal, 4=low)', '0')
.option('--prefix <prefix>', 'Identifier prefix', 'T')
.option('--json [fields]', 'Output JSON')
.action(
async (options: {
agent?: string;
instruction: string;
json?: string | boolean;
name?: string;
parent?: string;
prefix?: string;
priority?: string;
}) => {
const client = await getTrpcClient();
const input: Record<string, any> = {
instruction: options.instruction,
};
if (options.name) input.name = options.name;
if (options.agent) input.assigneeAgentId = options.agent;
if (options.parent) input.parentTaskId = options.parent;
if (options.priority) input.priority = Number.parseInt(options.priority, 10);
if (options.prefix) input.identifierPrefix = options.prefix;
const result = await client.task.create.mutate(input as any);
if (options.json !== undefined) {
outputJson(result.data, options.json);
return;
}
log.info(`Task created: ${pc.bold(result.data.identifier)} ${result.data.name || ''}`);
},
);
// ── edit ──────────────────────────────────────────────
task
.command('edit <id>')
.description('Update a task')
.option('-n, --name <name>', 'Task name')
.option('-i, --instruction <text>', 'Task instruction')
.option('--agent <id>', 'Assign to agent')
.option('--priority <n>', 'Priority (0-4)')
.option('--heartbeat-interval <n>', 'Heartbeat interval in seconds')
.option('--heartbeat-timeout <n>', 'Heartbeat timeout in seconds (0 to disable)')
.option('--description <text>', 'Task description')
.option(
'--status <status>',
'Set status (backlog, running, paused, completed, failed, canceled)',
)
.option('--json [fields]', 'Output JSON')
.action(
async (
id: string,
options: {
agent?: string;
description?: string;
heartbeatInterval?: string;
heartbeatTimeout?: string;
instruction?: string;
json?: string | boolean;
name?: string;
priority?: string;
status?: string;
},
) => {
const client = await getTrpcClient();
// Handle --status separately (uses updateStatus API)
if (options.status) {
const valid = ['backlog', 'running', 'paused', 'completed', 'failed', 'canceled'];
if (!valid.includes(options.status)) {
log.error(`Invalid status "${options.status}". Must be one of: ${valid.join(', ')}`);
return;
}
const result = await client.task.updateStatus.mutate({ id, status: options.status });
log.info(`${pc.bold(result.data.identifier)}${options.status}`);
return;
}
const input: Record<string, any> = { id };
if (options.name) input.name = options.name;
if (options.instruction) input.instruction = options.instruction;
if (options.description) input.description = options.description;
if (options.agent) input.assigneeAgentId = options.agent;
if (options.priority) input.priority = Number.parseInt(options.priority, 10);
if (options.heartbeatInterval)
input.heartbeatInterval = Number.parseInt(options.heartbeatInterval, 10);
if (options.heartbeatTimeout !== undefined) {
const val = Number.parseInt(options.heartbeatTimeout, 10);
input.heartbeatTimeout = val === 0 ? null : val;
}
const result = await client.task.update.mutate(input as any);
if (options.json !== undefined) {
outputJson(result.data, typeof options.json === 'string' ? options.json : undefined);
return;
}
log.info(`Task updated: ${pc.bold(result.data.identifier)}`);
},
);
// ── delete ──────────────────────────────────────────────
task
.command('delete <id>')
.description('Delete a task')
.option('-y, --yes', 'Skip confirmation')
.action(async (id: string, options: { yes?: boolean }) => {
if (!options.yes) {
const ok = await confirm(`Delete task ${pc.bold(id)}?`);
if (!ok) return;
}
const client = await getTrpcClient();
await client.task.delete.mutate({ id });
log.info(`Task ${pc.bold(id)} deleted.`);
});
// ── clear ──────────────────────────────────────────────
task
.command('clear')
.description('Delete all tasks')
.option('-y, --yes', 'Skip confirmation')
.action(async (options: { yes?: boolean }) => {
if (!options.yes) {
const ok = await confirm(`Delete ${pc.red('ALL')} tasks? This cannot be undone.`);
if (!ok) return;
}
const client = await getTrpcClient();
const result = (await client.task.clearAll.mutate()) as any;
log.info(`${result.count} task(s) deleted.`);
});
// ── tree ──────────────────────────────────────────────
task
.command('tree <id>')
.description('Show task tree (subtasks + dependencies)')
.option('--json [fields]', 'Output JSON')
.action(async (id: string, options: { json?: string | boolean }) => {
const client = await getTrpcClient();
const result = await client.task.getTaskTree.query({ id });
if (options.json !== undefined) {
outputJson(result.data, options.json);
return;
}
if (!result.data || result.data.length === 0) {
log.info('No tasks found.');
return;
}
// Build tree display (raw SQL returns snake_case)
const taskMap = new Map<string, any>();
for (const t of result.data) taskMap.set(t.id, t);
const printNode = (taskId: string, indent: number) => {
const t = taskMap.get(taskId);
if (!t) return;
const prefix = indent === 0 ? '' : ' '.repeat(indent) + '├── ';
const name = t.name || t.identifier || '';
const status = t.status || 'pending';
const identifier = t.identifier || t.id;
console.log(`${prefix}${pc.dim(identifier)} ${statusBadge(status)} ${name}`);
// Print children (handle both camelCase and snake_case)
for (const child of result.data) {
const childParent = child.parentTaskId || child.parent_task_id;
if (childParent === taskId) {
printNode(child.id, indent + 1);
}
}
};
// Find root - resolve identifier first
const resolved = await client.task.find.query({ id });
const rootId = resolved.data.id;
const root = result.data.find((t: any) => t.id === rootId);
if (root) printNode(root.id, 0);
else log.info('Root task not found in tree.');
});
// Register subcommand groups
registerLifecycleCommands(task);
registerCheckpointCommands(task);
registerReviewCommands(task);
registerDepCommands(task);
registerTopicCommands(task);
registerDocCommands(task);
}
+303
View File
@@ -0,0 +1,303 @@
import type { Command } from 'commander';
import pc from 'picocolors';
import { getTrpcClient } from '../../api/client';
import { getAuthInfo } from '../../api/http';
import { streamAgentEvents } from '../../utils/agentStream';
import { log } from '../../utils/logger';
export function registerLifecycleCommands(task: Command) {
// ── start ──────────────────────────────────────────────
task
.command('start <id>')
.description('Start a task (pending → running)')
.option('--no-run', 'Only update status, do not trigger agent execution')
.option('-p, --prompt <text>', 'Additional context for the agent')
.option('-f, --follow', 'Follow agent output in real-time (default: run in background)')
.option('--json', 'Output full JSON event stream')
.option('-v, --verbose', 'Show detailed tool call info')
.action(
async (
id: string,
options: {
follow?: boolean;
json?: boolean;
prompt?: string;
run?: boolean;
verbose?: boolean;
},
) => {
const client = await getTrpcClient();
// Check if already running
const taskDetail = await client.task.find.query({ id });
if (taskDetail.data.status === 'running') {
log.info(`Task ${pc.bold(taskDetail.data.identifier)} is already running.`);
return;
}
const statusResult = await client.task.updateStatus.mutate({ id, status: 'running' });
log.info(`Task ${pc.bold(statusResult.data.identifier)} started.`);
// Auto-run unless --no-run
if (options.run === false) return;
// Default agent to inbox if not assigned
if (!taskDetail.data.assigneeAgentId) {
await client.task.update.mutate({ assigneeAgentId: 'inbox', id });
log.info(`Assigned default agent: ${pc.dim('inbox')}`);
}
const result = (await client.task.run.mutate({
id,
...(options.prompt && { prompt: options.prompt }),
})) as any;
if (!result.success) {
log.error(`Failed to run task: ${result.error || result.message || 'Unknown error'}`);
process.exit(1);
}
log.info(
`Operation: ${pc.dim(result.operationId)} · Topic: ${pc.dim(result.topicId || 'n/a')}`,
);
if (!options.follow) {
log.info(
`Agent running in background. Use ${pc.dim(`lh task view ${id}`)} to check status.`,
);
return;
}
const { serverUrl, headers } = await getAuthInfo();
const streamUrl = `${serverUrl}/api/agent/stream?operationId=${encodeURIComponent(result.operationId)}`;
await streamAgentEvents(streamUrl, headers, {
json: options.json,
verbose: options.verbose,
});
// Send heartbeat after completion
try {
await client.task.heartbeat.mutate({ id });
} catch {
// ignore heartbeat errors
}
},
);
// ── run ──────────────────────────────────────────────
task
.command('run <id>')
.description('Run a task — trigger agent execution')
.option('-p, --prompt <text>', 'Additional context for the agent')
.option('-c, --continue <topicId>', 'Continue running on an existing topic')
.option('-f, --follow', 'Follow agent output in real-time (default: run in background)')
.option('--topics <n>', 'Run N topics in sequence (default: 1, implies --follow)', '1')
.option('--delay <s>', 'Delay between topics in seconds', '0')
.option('--json', 'Output full JSON event stream')
.option('-v, --verbose', 'Show detailed tool call info')
.action(
async (
id: string,
options: {
continue?: string;
delay?: string;
follow?: boolean;
json?: boolean;
prompt?: string;
topics?: string;
verbose?: boolean;
},
) => {
const topicCount = Number.parseInt(options.topics || '1', 10);
const delaySec = Number.parseInt(options.delay || '0', 10);
// --topics > 1 implies --follow
const shouldFollow = options.follow || topicCount > 1;
for (let i = 0; i < topicCount; i++) {
if (i > 0) {
log.info(`\n${'─'.repeat(60)}`);
log.info(`Topic ${i + 1}/${topicCount}`);
if (delaySec > 0) {
log.info(`Waiting ${delaySec}s before next topic...`);
await new Promise((r) => setTimeout(r, delaySec * 1000));
}
}
const client = await getTrpcClient();
// Auto-assign inbox agent on first topic if not assigned
if (i === 0) {
const taskDetail = await client.task.find.query({ id });
if (!taskDetail.data.assigneeAgentId) {
await client.task.update.mutate({ assigneeAgentId: 'inbox', id });
log.info(`Assigned default agent: ${pc.dim('inbox')}`);
}
}
// Only pass extra prompt and continue on first topic
const result = (await client.task.run.mutate({
id,
...(i === 0 && options.prompt && { prompt: options.prompt }),
...(i === 0 && options.continue && { continueTopicId: options.continue }),
})) as any;
if (!result.success) {
log.error(`Failed to run task: ${result.error || result.message || 'Unknown error'}`);
process.exit(1);
}
const operationId = result.operationId;
if (i === 0) {
log.info(`Task ${pc.bold(result.taskIdentifier)} running`);
}
log.info(`Operation: ${pc.dim(operationId)} · Topic: ${pc.dim(result.topicId || 'n/a')}`);
if (!shouldFollow) {
log.info(
`Agent running in background. Use ${pc.dim(`lh task view ${id}`)} to check status.`,
);
return;
}
// Connect to SSE stream and wait for completion
const { serverUrl, headers } = await getAuthInfo();
const streamUrl = `${serverUrl}/api/agent/stream?operationId=${encodeURIComponent(operationId)}`;
await streamAgentEvents(streamUrl, headers, {
json: options.json,
verbose: options.verbose,
});
// Update heartbeat after each topic
try {
await client.task.heartbeat.mutate({ id });
} catch {
// ignore heartbeat errors
}
}
},
);
// ── comment ──────────────────────────────────────────────
task
.command('comment <id>')
.description('Add a comment to a task')
.requiredOption('-m, --message <text>', 'Comment content')
.action(async (id: string, options: { message: string }) => {
const client = await getTrpcClient();
await client.task.addComment.mutate({ content: options.message, id });
log.info('Comment added.');
});
// ── pause ──────────────────────────────────────────────
task
.command('pause <id>')
.description('Pause a running task')
.action(async (id: string) => {
const client = await getTrpcClient();
const result = await client.task.updateStatus.mutate({ id, status: 'paused' });
log.info(`Task ${pc.bold(result.data.identifier)} paused.`);
});
// ── resume ──────────────────────────────────────────────
task
.command('resume <id>')
.description('Resume a paused task')
.action(async (id: string) => {
const client = await getTrpcClient();
const result = await client.task.updateStatus.mutate({ id, status: 'running' });
log.info(`Task ${pc.bold(result.data.identifier)} resumed.`);
});
// ── complete ──────────────────────────────────────────────
task
.command('complete <id>')
.description('Mark a task as completed')
.action(async (id: string) => {
const client = await getTrpcClient();
const result = (await client.task.updateStatus.mutate({ id, status: 'completed' })) as any;
log.info(`Task ${pc.bold(result.data.identifier)} completed.`);
if (result.unlocked?.length > 0) {
log.info(`Unlocked: ${result.unlocked.map((id: string) => pc.bold(id)).join(', ')}`);
}
if (result.paused?.length > 0) {
log.info(
`Paused (checkpoint): ${result.paused.map((id: string) => pc.yellow(id)).join(', ')}`,
);
}
if (result.checkpointTriggered) {
log.info(`${pc.yellow('Checkpoint triggered')} — parent task paused for review.`);
}
if (result.allSubtasksDone) {
log.info(`All subtasks of parent task completed.`);
}
});
// ── cancel ──────────────────────────────────────────────
task
.command('cancel <id>')
.description('Cancel a task')
.action(async (id: string) => {
const client = await getTrpcClient();
const result = await client.task.updateStatus.mutate({ id, status: 'canceled' });
log.info(`Task ${pc.bold(result.data.identifier)} canceled.`);
});
// ── sort ──────────────────────────────────────────────
task
.command('sort <id> <identifiers...>')
.description('Reorder subtasks (e.g. lh task sort T-1 T-2 T-4 T-3)')
.action(async (id: string, identifiers: string[]) => {
const client = await getTrpcClient();
const result = (await client.task.reorderSubtasks.mutate({
id,
order: identifiers,
})) as any;
log.info('Subtasks reordered:');
for (const item of result.data) {
console.log(` ${pc.dim(`#${item.sortOrder}`)} ${item.identifier}`);
}
});
// ── heartbeat ──────────────────────────────────────────────
task
.command('heartbeat <id>')
.description('Manually send heartbeat for a running task')
.action(async (id: string) => {
const client = await getTrpcClient();
await client.task.heartbeat.mutate({ id });
log.info(`Heartbeat sent for ${pc.bold(id)}.`);
});
// ── watchdog ──────────────────────────────────────────────
task
.command('watchdog')
.description('Run watchdog check — detect and fail stuck tasks')
.action(async () => {
const client = await getTrpcClient();
const result = (await client.task.watchdog.mutate()) as any;
if (result.failed?.length > 0) {
log.info(
`${pc.red('Stuck tasks failed:')} ${result.failed.map((id: string) => pc.bold(id)).join(', ')}`,
);
} else {
log.info('No stuck tasks found.');
}
});
}
+306
View File
@@ -0,0 +1,306 @@
import type { Command } from 'commander';
import pc from 'picocolors';
import { getTrpcClient } from '../../api/client';
import { printTable, truncate } from '../../utils/format';
import { log } from '../../utils/logger';
export function registerReviewCommands(task: Command) {
// ── review ──────────────────────────────────────────────
const rv = task.command('review').description('Manage task review (LLM-as-Judge)');
rv.command('view <id>')
.description('View review config for a task')
.action(async (id: string) => {
const client = await getTrpcClient();
const result = await client.task.getReview.query({ id });
const r = result.data as any;
if (!r || !r.enabled) {
log.info('Review not configured for this task.');
return;
}
console.log(`\n${pc.bold('Review config:')}`);
console.log(` enabled: ${r.enabled}`);
if (r.judge?.model)
console.log(` judge: ${r.judge.model}${r.judge.provider ? ` (${r.judge.provider})` : ''}`);
console.log(` maxIterations: ${r.maxIterations}`);
console.log(` autoRetry: ${r.autoRetry}`);
if (r.rubrics?.length > 0) {
console.log(` rubrics:`);
for (let i = 0; i < r.rubrics.length; i++) {
const rb = r.rubrics[i];
const threshold = rb.threshold ? `${Math.round(rb.threshold * 100)}%` : '';
const typeTag = pc.dim(`[${rb.type}]`);
let configInfo = '';
if (rb.type === 'llm-rubric') configInfo = rb.config?.criteria || '';
else if (rb.type === 'contains' || rb.type === 'equals')
configInfo = `value="${rb.config?.value}"`;
else if (rb.type === 'regex') configInfo = `pattern="${rb.config?.pattern}"`;
console.log(` ${i + 1}. ${rb.name} ${typeTag}${threshold} ${pc.dim(configInfo)}`);
}
} else {
console.log(` rubrics: ${pc.dim('(none)')}`);
}
console.log();
});
rv.command('set <id>')
.description('Enable review and configure judge settings')
.option('--model <model>', 'Judge model')
.option('--provider <provider>', 'Judge provider')
.option('--max-iterations <n>', 'Max review iterations', '3')
.option('--no-auto-retry', 'Disable auto retry on failure')
.option('--recursive', 'Apply to all subtasks as well')
.action(
async (
id: string,
options: {
autoRetry?: boolean;
maxIterations?: string;
model?: string;
provider?: string;
recursive?: boolean;
},
) => {
const client = await getTrpcClient();
// Read current review config to preserve rubrics
const current = (await client.task.getReview.query({ id })).data as any;
const existingRubrics = current?.rubrics || [];
const review = {
autoRetry: options.autoRetry !== false,
enabled: true,
judge: {
...(options.model && { model: options.model }),
...(options.provider && { provider: options.provider }),
},
maxIterations: Number.parseInt(options.maxIterations || '3', 10),
rubrics: existingRubrics,
};
await client.task.updateReview.mutate({ id, review });
if (options.recursive) {
const subtasks = await client.task.getSubtasks.query({ id });
for (const s of subtasks.data || []) {
const subCurrent = (await client.task.getReview.query({ id: s.id })).data as any;
await client.task.updateReview.mutate({
id: s.id,
review: { ...review, rubrics: subCurrent?.rubrics || existingRubrics },
});
}
log.info(
`Review enabled for ${pc.bold(id)} + ${(subtasks.data || []).length} subtask(s).`,
);
} else {
log.info('Review enabled.');
}
},
);
// ── review criteria ──────────────────────────────────────
const rc = rv.command('criteria').description('Manage review rubrics');
rc.command('list <id>')
.description('List review rubrics for a task')
.action(async (id: string) => {
const client = await getTrpcClient();
const result = await client.task.getReview.query({ id });
const r = result.data as any;
const rubrics = r?.rubrics || [];
if (rubrics.length === 0) {
log.info('No rubrics configured.');
return;
}
const rows = rubrics.map((r: any, i: number) => {
const config = r.config || {};
const configStr =
r.type === 'llm-rubric'
? config.criteria || ''
: r.type === 'contains' || r.type === 'equals'
? `value: "${config.value}"`
: r.type === 'regex'
? `pattern: "${config.pattern}"`
: JSON.stringify(config);
return [
String(i + 1),
r.name,
r.type,
r.threshold ? `${Math.round(r.threshold * 100)}%` : '-',
String(r.weight ?? 1),
truncate(configStr, 40),
];
});
printTable(rows, ['#', 'NAME', 'TYPE', 'THRESHOLD', 'WEIGHT', 'CONFIG']);
});
rc.command('add <id>')
.description('Add a review rubric')
.requiredOption('-n, --name <name>', 'Rubric name (e.g. "内容准确性")')
.option('--type <type>', 'Rubric type (default: llm-rubric)', 'llm-rubric')
.option('-t, --threshold <n>', 'Pass threshold 0-100 (converted to 0-1)')
.option('-d, --description <text>', 'Criteria description (for llm-rubric type)')
.option('--value <value>', 'Expected value (for contains/equals type)')
.option('--pattern <pattern>', 'Regex pattern (for regex type)')
.option('-w, --weight <n>', 'Weight for scoring (default: 1)')
.option('--recursive', 'Add to all subtasks as well')
.action(
async (
id: string,
options: {
description?: string;
name: string;
pattern?: string;
recursive?: boolean;
threshold?: string;
type: string;
value?: string;
weight?: string;
},
) => {
const client = await getTrpcClient();
// Build rubric config based on type
const buildConfig = (): Record<string, any> | null => {
switch (options.type) {
case 'llm-rubric': {
return { criteria: options.description || options.name };
}
case 'contains':
case 'equals':
case 'starts-with':
case 'ends-with': {
if (!options.value) {
log.error(`--value is required for type "${options.type}"`);
return null;
}
return { value: options.value };
}
case 'regex': {
if (!options.pattern) {
log.error('--pattern is required for type "regex"');
return null;
}
return { pattern: options.pattern };
}
default: {
return { criteria: options.description || options.name };
}
}
};
const config = buildConfig();
if (!config) return;
const rubric: Record<string, any> = {
config,
id: `rubric-${Date.now()}`,
name: options.name,
type: options.type,
weight: options.weight ? Number.parseFloat(options.weight) : 1,
};
if (options.threshold) {
rubric.threshold = Number.parseInt(options.threshold, 10) / 100;
}
const addToTask = async (taskId: string) => {
const current = (await client.task.getReview.query({ id: taskId })).data as any;
const rubrics = current?.rubrics || [];
// Replace if same name exists, otherwise append
const filtered = rubrics.filter((r: any) => r.name !== options.name);
filtered.push(rubric);
await client.task.updateReview.mutate({
id: taskId,
review: {
autoRetry: current?.autoRetry ?? true,
enabled: current?.enabled ?? true,
judge: current?.judge ?? {},
maxIterations: current?.maxIterations ?? 3,
rubrics: filtered,
},
});
};
await addToTask(id);
if (options.recursive) {
const subtasks = await client.task.getSubtasks.query({ id });
for (const s of subtasks.data || []) {
await addToTask(s.id);
}
log.info(
`Rubric "${options.name}" [${options.type}] added to ${pc.bold(id)} + ${(subtasks.data || []).length} subtask(s).`,
);
} else {
log.info(`Rubric "${options.name}" [${options.type}] added.`);
}
},
);
rc.command('rm <id>')
.description('Remove a review rubric')
.requiredOption('-n, --name <name>', 'Rubric name to remove')
.option('--recursive', 'Remove from all subtasks as well')
.action(async (id: string, options: { name: string; recursive?: boolean }) => {
const client = await getTrpcClient();
const removeFromTask = async (taskId: string) => {
const current = (await client.task.getReview.query({ id: taskId })).data as any;
if (!current) return;
const rubrics = (current.rubrics || []).filter((r: any) => r.name !== options.name);
await client.task.updateReview.mutate({
id: taskId,
review: { ...current, rubrics },
});
};
await removeFromTask(id);
if (options.recursive) {
const subtasks = await client.task.getSubtasks.query({ id });
for (const s of subtasks.data || []) {
await removeFromTask(s.id);
}
log.info(
`Rubric "${options.name}" removed from ${pc.bold(id)} + ${(subtasks.data || []).length} subtask(s).`,
);
} else {
log.info(`Rubric "${options.name}" removed.`);
}
});
rv.command('run <id>')
.description('Manually run review on content')
.requiredOption('--content <text>', 'Content to review')
.action(async (id: string, options: { content: string }) => {
const client = await getTrpcClient();
const result = (await client.task.runReview.mutate({
content: options.content,
id,
})) as any;
const r = result.data;
console.log(
`\n${r.passed ? pc.green('✓ Review passed') : pc.red('✗ Review failed')} (${r.overallScore}%)`,
);
for (const s of r.rubricResults || []) {
const icon = s.passed ? pc.green('✓') : pc.red('✗');
const pct = Math.round(s.score * 100);
console.log(` ${icon} ${s.rubricId}: ${pct}%${s.reason ? `${s.reason}` : ''}`);
}
console.log();
});
}
+117
View File
@@ -0,0 +1,117 @@
import type { Command } from 'commander';
import pc from 'picocolors';
import { getTrpcClient } from '../../api/client';
import { confirm, outputJson, printTable, timeAgo, truncate } from '../../utils/format';
import { log } from '../../utils/logger';
import { statusBadge } from './helpers';
export function registerTopicCommands(task: Command) {
// ── topic ──────────────────────────────────────────────
const tp = task.command('topic').description('Manage task topics');
tp.command('list <id>')
.description('List topics for a task')
.option('--json [fields]', 'Output JSON')
.action(async (id: string, options: { json?: string | boolean }) => {
const client = await getTrpcClient();
const result = await client.task.getTopics.query({ id });
if (options.json !== undefined) {
outputJson(result.data, options.json);
return;
}
if (!result.data || result.data.length === 0) {
log.info('No topics found for this task.');
return;
}
const rows = result.data.map((t: any) => [
`#${t.seq}`,
t.id,
statusBadge(t.status || 'running'),
truncate(t.title || 'Untitled', 40),
t.operationId ? pc.dim(truncate(t.operationId, 20)) : '-',
timeAgo(t.createdAt),
]);
printTable(rows, ['SEQ', 'TOPIC ID', 'STATUS', 'TITLE', 'OPERATION', 'CREATED']);
});
tp.command('view <id> <topicId>')
.description('View messages of a topic (topicId can be a seq number like "1")')
.option('--json [fields]', 'Output JSON')
.action(async (id: string, topicId: string, options: { json?: string | boolean }) => {
const client = await getTrpcClient();
let resolvedTopicId = topicId;
// If it's a number, treat as seq index
const seqNum = Number.parseInt(topicId, 10);
if (!Number.isNaN(seqNum) && String(seqNum) === topicId) {
const topicsResult = await client.task.getTopics.query({ id });
const match = (topicsResult.data || []).find((t: any) => t.seq === seqNum);
if (!match) {
log.error(`Topic #${seqNum} not found for this task.`);
return;
}
resolvedTopicId = match.id;
log.info(
`Topic #${seqNum}: ${pc.bold(match.title || 'Untitled')} ${pc.dim(resolvedTopicId)}`,
);
}
const messages = await client.message.getMessages.query({ topicId: resolvedTopicId });
const items = Array.isArray(messages) ? messages : [];
if (options.json !== undefined) {
outputJson(items, options.json);
return;
}
if (items.length === 0) {
log.info('No messages in this topic.');
return;
}
console.log();
for (const msg of items) {
const role =
msg.role === 'assistant'
? pc.green('Assistant')
: msg.role === 'user'
? pc.blue('User')
: pc.dim(msg.role);
console.log(`${pc.bold(role)} ${pc.dim(timeAgo(msg.createdAt))}`);
if (msg.content) {
console.log(msg.content);
}
console.log();
}
});
tp.command('cancel <topicId>')
.description('Cancel a running topic and pause the task')
.action(async (topicId: string) => {
const client = await getTrpcClient();
await client.task.cancelTopic.mutate({ topicId });
log.info(`Topic ${pc.bold(topicId)} canceled. Task paused.`);
});
tp.command('delete <topicId>')
.description('Delete a topic and its messages')
.option('-y, --yes', 'Skip confirmation')
.action(async (topicId: string, options: { yes?: boolean }) => {
if (!options.yes) {
const ok = await confirm(`Delete topic ${pc.bold(topicId)} and all its messages?`);
if (!ok) return;
}
const client = await getTrpcClient();
await client.task.deleteTopic.mutate({ topicId });
log.info(`Topic ${pc.bold(topicId)} deleted.`);
});
}
+1
View File
@@ -0,0 +1 @@
export const CLI_API_KEY_ENV = 'LOBEHUB_CLI_API_KEY';
+2 -70
View File
@@ -1,71 +1,3 @@
import { createRequire } from 'node:module';
import { createProgram } from './program';
import { Command } from 'commander';
import { registerAgentCommand } from './commands/agent';
import { registerAgentGroupCommand } from './commands/agent-group';
import { registerBotCommand } from './commands/bot';
import { registerCompletionCommand } from './commands/completion';
import { registerConfigCommand } from './commands/config';
import { registerConnectCommand } from './commands/connect';
import { registerCronCommand } from './commands/cron';
import { registerDeviceCommand } from './commands/device';
import { registerDocCommand } from './commands/doc';
import { registerEvalCommand } from './commands/eval';
import { registerFileCommand } from './commands/file';
import { registerGenerateCommand } from './commands/generate';
import { registerKbCommand } from './commands/kb';
import { registerLoginCommand } from './commands/login';
import { registerLogoutCommand } from './commands/logout';
import { registerMemoryCommand } from './commands/memory';
import { registerMessageCommand } from './commands/message';
import { registerModelCommand } from './commands/model';
import { registerPluginCommand } from './commands/plugin';
import { registerProviderCommand } from './commands/provider';
import { registerSearchCommand } from './commands/search';
import { registerSessionGroupCommand } from './commands/session-group';
import { registerSkillCommand } from './commands/skill';
import { registerStatusCommand } from './commands/status';
import { registerThreadCommand } from './commands/thread';
import { registerTopicCommand } from './commands/topic';
import { registerUserCommand } from './commands/user';
const require = createRequire(import.meta.url);
const { version } = require('../package.json');
const program = new Command();
program
.name('lh')
.description('LobeHub CLI - manage and connect to LobeHub services')
.version(version);
registerLoginCommand(program);
registerLogoutCommand(program);
registerCompletionCommand(program);
registerConnectCommand(program);
registerDeviceCommand(program);
registerStatusCommand(program);
registerDocCommand(program);
registerSearchCommand(program);
registerKbCommand(program);
registerMemoryCommand(program);
registerAgentCommand(program);
registerAgentGroupCommand(program);
registerBotCommand(program);
registerCronCommand(program);
registerGenerateCommand(program);
registerFileCommand(program);
registerSkillCommand(program);
registerSessionGroupCommand(program);
registerThreadCommand(program);
registerTopicCommand(program);
registerMessageCommand(program);
registerModelCommand(program);
registerProviderCommand(program);
registerPluginCommand(program);
registerUserCommand(program);
registerConfigCommand(program);
registerEvalCommand(program);
program.parse();
createProgram().parse();
+17
View File
@@ -0,0 +1,17 @@
import { mkdir, writeFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { cliVersion, createProgram } from '../program';
import { generateAliasManPage, generateRootManPage } from './roff';
const outputDir = fileURLToPath(new URL('../../man/man1/', import.meta.url));
await mkdir(outputDir, { recursive: true });
const program = createProgram();
await Promise.all([
writeFile(`${outputDir}lh.1`, generateRootManPage(program, cliVersion)),
writeFile(`${outputDir}lobe.1`, generateAliasManPage('lh')),
writeFile(`${outputDir}lobehub.1`, generateAliasManPage('lh')),
]);
+28
View File
@@ -0,0 +1,28 @@
import { Command } from 'commander';
import { describe, expect, it } from 'vitest';
import { generateAliasManPage, generateRootManPage } from './roff';
describe('roff manual generator', () => {
it('renders a root man page from the command tree', () => {
const program = new Command();
program.name('lh').description('Sample CLI').version('1.0.0');
program.command('generate').alias('gen').description('Generate content');
program.command('login').description('Log in');
const output = generateRootManPage(program, '1.2.3');
expect(output).toContain('.TH LH 1 "" "@lobehub/cli 1.2.3" "User Commands"');
expect(output).toContain('.SH COMMANDS');
expect(output).toContain('.B generate');
expect(output).toContain('Generate content Alias: gen.');
expect(output).toContain('.B login');
expect(output).toContain('.SH OPTIONS');
});
it('renders alias man pages as so links', () => {
expect(generateAliasManPage('lh')).toBe('.so man1/lh.1\n');
});
});
+148
View File
@@ -0,0 +1,148 @@
import type { Command } from 'commander';
const ROOT_ALIASES = ['lobe', 'lobehub'];
const HELP_COMMAND_NAME = 'help';
interface RoffDefinition {
description: string;
term: string;
}
const FILE_ENTRIES = [
{
description: 'Encrypted access and refresh tokens.',
path: '~/.lobehub/credentials.json',
},
{
description: 'CLI settings such as server and gateway URLs.',
path: '~/.lobehub/settings.json',
},
{
description: 'Background daemon PID file.',
path: '~/.lobehub/daemon.pid',
},
{
description: 'Background daemon status metadata.',
path: '~/.lobehub/daemon.status',
},
{
description: 'Background daemon log output.',
path: '~/.lobehub/daemon.log',
},
] as const;
const EXAMPLES = [
{
command: 'lh login',
description: 'Start interactive login in the browser.',
},
{
command: 'lh connect --daemon',
description: 'Start the device gateway connection in the background.',
},
{
command: 'lh search -q "gpt-5"',
description: 'Search local resources for a query.',
},
{
command: 'lh generate text "Write release notes"',
description: 'Generate text from a prompt.',
},
{
command: 'lh man generate',
description: 'Show the built-in manual for the generate command group.',
},
] as const;
export function generateRootManPage(program: Command, version: string) {
const help = program.createHelp();
const commands = getVisibleCommands(program).map((command) => ({
description: formatCommandDescription(help.subcommandDescription(command), command.aliases()),
term: command.name(),
}));
const options = help.visibleOptions(program).map((option) => ({
description: help.optionDescription(option),
term: help.optionTerm(option),
}));
const lines = [
'.\\" Code generated by `npm run man:generate`; DO NOT EDIT.',
'.\\" Manual command details come from the Commander command tree.',
`.TH LH 1 "" "${escapeRoff(`@lobehub/cli ${version}`)}" "User Commands"`,
'.SH NAME',
`lh \\- ${escapeRoff(program.description() || 'LobeHub CLI')}`,
'.SH SYNOPSIS',
...formatSynopsisLines(),
'.SH DESCRIPTION',
escapeRoff(
`${program.name()} is the command-line interface for LobeHub. It provides authentication, device gateway connectivity, content generation, resource search, and management commands for agents, files, models, providers, plugins, knowledge bases, threads, topics, and related resources.`,
),
'.PP',
'For command-specific manuals, use the built-in manual command:',
'.PP',
'.RS',
'.B lh man',
'[\\fICOMMAND\\fR]...',
'.RE',
'.SH COMMANDS',
...formatDefinitionSection(commands, 'B'),
'.SH OPTIONS',
...formatDefinitionSection(options, 'B'),
'.SH FILES',
...FILE_ENTRIES.flatMap((entry) => [
'.TP',
`.I ${escapeRoff(entry.path)}`,
escapeRoff(entry.description),
]),
'.PP',
'The base directory can be overridden with the',
'.B LOBEHUB_CLI_HOME',
'environment variable.',
'.SH EXAMPLES',
...EXAMPLES.flatMap((example) => [
'.TP',
`.B ${escapeRoff(example.command)}`,
escapeRoff(example.description),
]),
'.SH SEE ALSO',
'.BR lobe (1),',
'.BR lobehub (1)',
];
return `${lines.join('\n')}\n`;
}
export function generateAliasManPage(target: string) {
return `.so man1/${target}.1\n`;
}
function formatSynopsisLines() {
return ['lh', ...ROOT_ALIASES]
.flatMap((binary) => [`.B ${binary}`, '[\\fIOPTION\\fR]...', '[\\fICOMMAND\\fR]', '.br'])
.slice(0, -1);
}
function getVisibleCommands(command: Command) {
return command
.createHelp()
.visibleCommands(command)
.filter((subcommand) => subcommand.name() !== HELP_COMMAND_NAME);
}
function formatCommandDescription(description: string, aliases: string[]) {
if (aliases.length === 0) return description;
return `${description} Alias: ${aliases.join(', ')}.`;
}
function formatDefinitionSection(items: RoffDefinition[], macro: 'B' | 'I') {
return items.flatMap((item) => [
'.TP',
`.${macro} ${escapeRoff(item.term)}`,
escapeRoff(item.description),
]);
}
function escapeRoff(value: string) {
return value.replaceAll('\\', '\\\\').replaceAll('-', '\\-');
}
+77
View File
@@ -0,0 +1,77 @@
import { createRequire } from 'node:module';
import { Command } from 'commander';
import { registerAgentCommand } from './commands/agent';
import { registerAgentGroupCommand } from './commands/agent-group';
import { registerBotCommand } from './commands/bot';
import { registerCompletionCommand } from './commands/completion';
import { registerConfigCommand } from './commands/config';
import { registerConnectCommand } from './commands/connect';
import { registerCronCommand } from './commands/cron';
import { registerDeviceCommand } from './commands/device';
import { registerDocCommand } from './commands/doc';
import { registerEvalCommand } from './commands/eval';
import { registerFileCommand } from './commands/file';
import { registerGenerateCommand } from './commands/generate';
import { registerKbCommand } from './commands/kb';
import { registerLoginCommand } from './commands/login';
import { registerLogoutCommand } from './commands/logout';
import { registerManCommand } from './commands/man';
import { registerMemoryCommand } from './commands/memory';
import { registerMessageCommand } from './commands/message';
import { registerModelCommand } from './commands/model';
import { registerPluginCommand } from './commands/plugin';
import { registerProviderCommand } from './commands/provider';
import { registerSearchCommand } from './commands/search';
import { registerSessionGroupCommand } from './commands/session-group';
import { registerSkillCommand } from './commands/skill';
import { registerStatusCommand } from './commands/status';
import { registerThreadCommand } from './commands/thread';
import { registerTopicCommand } from './commands/topic';
import { registerUserCommand } from './commands/user';
const require = createRequire(import.meta.url);
const { version } = require('../package.json');
export function createProgram() {
const program = new Command();
program
.name('lh')
.description('LobeHub CLI - manage and connect to LobeHub services')
.version(version);
registerLoginCommand(program);
registerLogoutCommand(program);
registerCompletionCommand(program);
registerManCommand(program);
registerConnectCommand(program);
registerDeviceCommand(program);
registerStatusCommand(program);
registerDocCommand(program);
registerSearchCommand(program);
registerKbCommand(program);
registerMemoryCommand(program);
registerAgentCommand(program);
registerAgentGroupCommand(program);
registerBotCommand(program);
registerCronCommand(program);
registerGenerateCommand(program);
registerFileCommand(program);
registerSkillCommand(program);
registerSessionGroupCommand(program);
registerThreadCommand(program);
registerTopicCommand(program);
registerMessageCommand(program);
registerModelCommand(program);
registerProviderCommand(program);
registerPluginCommand(program);
registerUserCommand(program);
registerConfigCommand(program);
registerEvalCommand(program);
return program;
}
export { version as cliVersion };
+29 -2
View File
@@ -5,18 +5,19 @@ import path from 'node:path';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { log } from '../utils/logger';
import { loadSettings, saveSettings } from './index';
import { loadSettings, normalizeUrl, resolveServerUrl, saveSettings } from './index';
const tmpDir = path.join(os.tmpdir(), 'lobehub-cli-test-settings');
const settingsDir = path.join(tmpDir, '.lobehub');
const settingsFile = path.join(settingsDir, 'settings.json');
const originalServer = process.env.LOBEHUB_SERVER;
vi.mock('node:os', async (importOriginal) => {
const actual = await importOriginal<Record<string, any>>();
return {
...actual,
default: {
...actual['default'],
...actual.default,
homedir: () => path.join(os.tmpdir(), 'lobehub-cli-test-settings'),
},
};
@@ -31,10 +32,12 @@ vi.mock('../utils/logger', () => ({
describe('settings', () => {
beforeEach(() => {
fs.mkdirSync(tmpDir, { recursive: true });
delete process.env.LOBEHUB_SERVER;
});
afterEach(() => {
fs.rmSync(tmpDir, { force: true, recursive: true });
process.env.LOBEHUB_SERVER = originalServer;
vi.clearAllMocks();
});
@@ -64,4 +67,28 @@ describe('settings', () => {
expect(loadSettings()).toBeNull();
expect(log.warn).toHaveBeenCalledWith(expect.stringContaining('Please delete this file'));
});
it('should normalize trailing slashes', () => {
expect(normalizeUrl('https://self-hosted.example.com/')).toBe(
'https://self-hosted.example.com',
);
expect(normalizeUrl(undefined)).toBeUndefined();
});
it('should prefer LOBEHUB_SERVER over settings', () => {
saveSettings({ serverUrl: 'https://settings.example.com/' });
process.env.LOBEHUB_SERVER = 'https://env.example.com/';
expect(resolveServerUrl()).toBe('https://env.example.com');
});
it('should fall back to settings then official server', () => {
saveSettings({ serverUrl: 'https://settings.example.com/' });
expect(resolveServerUrl()).toBe('https://settings.example.com');
fs.unlinkSync(settingsFile);
expect(resolveServerUrl()).toBe('https://app.lobehub.com');
});
});
+8 -1
View File
@@ -14,10 +14,17 @@ const LOBEHUB_DIR_NAME = process.env.LOBEHUB_CLI_HOME || '.lobehub';
const SETTINGS_DIR = path.join(os.homedir(), LOBEHUB_DIR_NAME);
const SETTINGS_FILE = path.join(SETTINGS_DIR, 'settings.json');
function normalizeUrl(url: string | undefined): string | undefined {
export function normalizeUrl(url: string | undefined): string | undefined {
return url ? url.replace(/\/$/, '') : undefined;
}
export function resolveServerUrl(): string {
const envServerUrl = normalizeUrl(process.env.LOBEHUB_SERVER);
const settingsServerUrl = normalizeUrl(loadSettings()?.serverUrl);
return envServerUrl || settingsServerUrl || OFFICIAL_SERVER_URL;
}
export function saveSettings(settings: StoredSettings): void {
const serverUrl = normalizeUrl(settings.serverUrl);
const gatewayUrl = normalizeUrl(settings.gatewayUrl);
+1 -1
View File
@@ -87,7 +87,7 @@ function stripAnsi(s: string): string {
* Calculate the display width of a string in the terminal.
* CJK characters and fullwidth symbols occupy 2 columns.
*/
function displayWidth(s: string): number {
export function displayWidth(s: string): number {
const plain = stripAnsi(s);
let width = 0;
for (const char of plain) {
+3 -2
View File
@@ -52,8 +52,9 @@ export default defineConfig({
minify: !isDev,
outDir: 'dist/main',
rollupOptions: {
// Native modules must be externalized to work correctly
external: getExternalDependencies(),
// Native modules must be externalized to work correctly.
// bufferutil and utf-8-validate are optional peer deps of ws that may not be installed.
external: [...getExternalDependencies(), 'bufferutil', 'utf-8-validate'],
output: {
// Prevent debug package from being bundled into index.js to avoid side-effect pollution
manualChunks(id) {
+2 -1
View File
@@ -50,6 +50,7 @@
"@electron-toolkit/tsconfig": "^2.0.0",
"@electron-toolkit/utils": "^4.0.0",
"@lobechat/desktop-bridge": "workspace:*",
"@lobechat/device-gateway-client": "workspace:*",
"@lobechat/electron-client-ipc": "workspace:*",
"@lobechat/electron-server-ipc": "workspace:*",
"@lobechat/file-loaders": "workspace:*",
@@ -66,7 +67,7 @@
"consola": "^3.4.2",
"cookie": "^1.1.1",
"cross-env": "^10.1.0",
"diff": "^8.0.2",
"diff": "^8.0.4",
"electron": "41.0.2",
"electron-builder": "^26.8.1",
"electron-devtools-installer": "4.0.0",
+1
View File
@@ -3,5 +3,6 @@ packages:
- '../../packages/electron-client-ipc'
- '../../packages/file-loaders'
- '../../packages/desktop-bridge'
- '../../packages/device-gateway-client'
- '../../packages/local-file-shell'
- '.'
+5
View File
@@ -28,6 +28,11 @@ export const defaultProxySettings: NetworkProxySettings = {
export const STORE_DEFAULTS: ElectronMainStore = {
dataSyncConfig: { storageMode: 'cloud' },
encryptedTokens: {},
gatewayDeviceDescription: '',
gatewayDeviceId: '',
gatewayDeviceName: '',
gatewayEnabled: true,
gatewayUrl: 'https://device-gateway.lobehub.com',
locale: 'auto',
networkProxy: defaultProxySettings,
shortcuts: DEFAULT_SHORTCUTS_CONFIG,
+19 -2
View File
@@ -9,6 +9,7 @@ import type {
} from '@lobechat/electron-client-ipc';
import { BrowserWindow, shell } from 'electron';
import GatewayConnectionService from '@/services/gatewayConnectionSrv';
import { appendVercelCookie } from '@/utils/http-headers';
import { createLogger } from '@/utils/logger';
@@ -43,14 +44,14 @@ export default class AuthCtr extends ControllerModule {
/**
* Polling related parameters
*/
private pollingInterval: NodeJS.Timeout | null = null;
private cachedRemoteUrl: string | null = null;
/**
* Auto-refresh timer
*/
private autoRefreshTimer: NodeJS.Timeout | null = null;
/**
@@ -531,6 +532,9 @@ export default class AuthCtr extends ControllerModule {
// Start auto-refresh timer
this.startAutoRefresh();
// Connect to device gateway after successful login
this.connectGateway();
return { success: true };
} catch (error) {
logger.error('Exchanging authorization code failed:', error);
@@ -538,6 +542,19 @@ export default class AuthCtr extends ControllerModule {
}
}
/**
* Connect to device gateway (fire-and-forget)
*/
private connectGateway() {
const gatewaySrv = this.app.getService(GatewayConnectionService);
if (gatewaySrv) {
logger.info('Triggering gateway connection after login');
gatewaySrv.connect().catch((error) => {
logger.error('Gateway connection after login failed:', error);
});
}
}
/**
* Broadcast token refreshed event
*/
@@ -0,0 +1,139 @@
import type { GatewayConnectionStatus } from '@lobechat/electron-client-ipc';
import GatewayConnectionService from '@/services/gatewayConnectionSrv';
import { ControllerModule, IpcMethod } from './index';
import LocalFileCtr from './LocalFileCtr';
import RemoteServerConfigCtr from './RemoteServerConfigCtr';
import ShellCommandCtr from './ShellCommandCtr';
/**
* GatewayConnectionCtr
*
* Thin IPC layer that delegates to GatewayConnectionService.
*/
export default class GatewayConnectionCtr extends ControllerModule {
static override readonly groupName = 'gatewayConnection';
// ─── Service Accessor ───
private get service() {
return this.app.getService(GatewayConnectionService);
}
private get remoteServerConfigCtr() {
return this.app.getController(RemoteServerConfigCtr);
}
private get localFileCtr() {
return this.app.getController(LocalFileCtr);
}
private get shellCommandCtr() {
return this.app.getController(ShellCommandCtr);
}
// ─── Lifecycle ───
afterAppReady() {
const srv = this.service;
srv.loadOrCreateDeviceId();
// Wire up token provider and refresher
srv.setTokenProvider(() => this.remoteServerConfigCtr.getAccessToken());
srv.setTokenRefresher(() => this.remoteServerConfigCtr.refreshAccessToken());
// Wire up tool call handler
srv.setToolCallHandler((apiName, args) => this.executeToolCall(apiName, args));
// Auto-connect if already logged in
this.tryAutoConnect();
}
// ─── IPC Methods (Renderer → Main) ───
@IpcMethod()
async connect(): Promise<{ error?: string; success: boolean }> {
this.app.storeManager.set('gatewayEnabled', true);
return this.service.connect();
}
@IpcMethod()
async disconnect(): Promise<{ success: boolean }> {
this.app.storeManager.set('gatewayEnabled', false);
return this.service.disconnect();
}
@IpcMethod()
async getConnectionStatus(): Promise<{ status: GatewayConnectionStatus }> {
return { status: this.service.getStatus() };
}
@IpcMethod()
async getDeviceInfo(): Promise<{
description: string;
deviceId: string;
hostname: string;
name: string;
platform: string;
}> {
return this.service.getDeviceInfo();
}
@IpcMethod()
async setDeviceName(params: { name: string }): Promise<{ success: boolean }> {
this.service.setDeviceName(params.name);
return { success: true };
}
@IpcMethod()
async setDeviceDescription(params: { description: string }): Promise<{ success: boolean }> {
this.service.setDeviceDescription(params.description);
return { success: true };
}
// ─── Auto Connect ───
private async tryAutoConnect() {
const gatewayEnabled = this.app.storeManager.get('gatewayEnabled');
if (!gatewayEnabled) return;
const isConfigured = await this.remoteServerConfigCtr.isRemoteServerConfigured();
if (!isConfigured) return;
const token = await this.remoteServerConfigCtr.getAccessToken();
if (!token) return;
await this.service.connect();
}
// ─── Tool Call Routing ───
private async executeToolCall(apiName: string, args: any): Promise<unknown> {
const methodMap: Record<string, () => Promise<unknown>> = {
editLocalFile: () => this.localFileCtr.handleEditFile(args),
globLocalFiles: () => this.localFileCtr.handleGlobFiles(args),
grepContent: () => this.localFileCtr.handleGrepContent(args),
listLocalFiles: () => this.localFileCtr.listLocalFiles(args),
moveLocalFiles: () => this.localFileCtr.handleMoveFiles(args),
readLocalFile: () => this.localFileCtr.readFile(args),
renameLocalFile: () => this.localFileCtr.handleRenameFile(args),
searchLocalFiles: () => this.localFileCtr.handleLocalFilesSearch(args),
writeLocalFile: () => this.localFileCtr.handleWriteFile(args),
getCommandOutput: () => this.shellCommandCtr.handleGetCommandOutput(args),
killCommand: () => this.shellCommandCtr.handleKillCommand(args),
runCommand: () => this.shellCommandCtr.handleRunCommand(args),
};
const handler = methodMap[apiName];
if (!handler) {
throw new Error(
`Tool "${apiName}" is not available on this device. It may not be supported in the current desktop version. Please skip this tool and try alternative approaches.`,
);
}
return handler();
}
}
@@ -1,8 +1,10 @@
import { constants } from 'node:fs';
import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
import { access, mkdir, readFile, realpath, rm, writeFile } from 'node:fs/promises';
import path from 'node:path';
import {
type AuditSafePathsParams,
type AuditSafePathsResult,
type EditLocalFileParams,
type EditLocalFileResult,
type GlobFilesParams,
@@ -52,6 +54,72 @@ import { ControllerModule, IpcMethod } from './index';
// Create logger
const logger = createLogger('controllers:LocalFileCtr');
const SAFE_PATH_PREFIXES = ['/tmp', '/var/tmp'] as const;
const normalizeAbsolutePath = (inputPath: string): string =>
path.normalize(path.isAbsolute(inputPath) ? inputPath : `/${inputPath}`);
const resolvePathWithScope = (inputPath: string, scope: string): string =>
path.isAbsolute(inputPath) ? inputPath : path.join(scope, inputPath);
const isWithinSafePathPrefixes = (targetPath: string, prefixes: readonly string[]): boolean =>
prefixes.some((prefix) => targetPath === prefix || targetPath.startsWith(`${prefix}${path.sep}`));
const resolveNearestExistingRealPath = async (targetPath: string): Promise<string | undefined> => {
let currentPath = targetPath;
while (true) {
try {
await access(currentPath, constants.F_OK);
return normalizeAbsolutePath(await realpath(currentPath));
} catch {
const parentPath = path.dirname(currentPath);
if (parentPath === currentPath) return undefined;
currentPath = parentPath;
}
}
};
const resolveSafePathRealPrefixes = async (): Promise<string[]> => {
const prefixes = new Set<string>(SAFE_PATH_PREFIXES);
for (const safePrefix of SAFE_PATH_PREFIXES) {
try {
prefixes.add(normalizeAbsolutePath(await realpath(safePrefix)));
} catch {
// Keep the lexical prefix if the platform does not expose this directory.
}
}
return [...prefixes];
};
const areAllPathsSafeOnDisk = async (
paths: string[],
resolveAgainstScope: string,
): Promise<boolean> => {
if (paths.length === 0) return false;
const safeRealPrefixes = await resolveSafePathRealPrefixes();
for (const currentPath of paths) {
const normalizedPath = normalizeAbsolutePath(
resolvePathWithScope(currentPath, resolveAgainstScope),
);
if (!isWithinSafePathPrefixes(normalizedPath, SAFE_PATH_PREFIXES)) {
return false;
}
const realPath = await resolveNearestExistingRealPath(normalizedPath);
if (!realPath || !isWithinSafePathPrefixes(realPath, safeRealPrefixes)) {
return false;
}
}
return true;
};
export default class LocalFileCtr extends ControllerModule {
static override readonly groupName = 'localSystem';
private get searchService() {
@@ -240,6 +308,18 @@ export default class LocalFileCtr extends ControllerModule {
return writeLocalFile({ content, path: filePath });
}
@IpcMethod()
async auditSafePaths({
paths,
resolveAgainstScope,
}: AuditSafePathsParams): Promise<AuditSafePathsResult> {
logger.debug('Auditing safe paths', { count: paths.length, resolveAgainstScope });
return {
allSafe: await areAllPathsSafeOnDisk(paths, resolveAgainstScope),
};
}
@IpcMethod()
async handlePrepareSkillDirectory({
forceRefresh,
@@ -6,6 +6,7 @@ import retry from 'async-retry';
import { safeStorage, session as electronSession } from 'electron';
import { OFFICIAL_CLOUD_SERVER } from '@/const/env';
import GatewayConnectionService from '@/services/gatewayConnectionSrv';
import { appendVercelCookie } from '@/utils/http-headers';
import { createLogger } from '@/utils/logger';
@@ -319,6 +320,13 @@ export default class RemoteServerConfigCtr extends ControllerModule {
// Also clear from persistent storage
logger.debug(`Deleting tokens from store key: ${this.encryptedTokensKey}`);
this.app.storeManager.delete(this.encryptedTokensKey);
// Disconnect gateway when tokens are cleared (logout / token refresh failure)
const gatewaySrv = this.app.getService(GatewayConnectionService);
if (gatewaySrv) {
logger.debug('Disconnecting gateway due to token clear');
await gatewaySrv.disconnect();
}
}
/**
@@ -1,4 +1,3 @@
import type { DataSyncConfig } from '@lobechat/electron-client-ipc';
import { BrowserWindow, shell } from 'electron';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
@@ -100,6 +99,7 @@ const mockApp = {
}
return null;
}),
getService: vi.fn(() => null),
} as unknown as App;
describe('AuthCtr', () => {
@@ -0,0 +1,606 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import type { App } from '@/core/App';
import GatewayConnectionService from '@/services/gatewayConnectionSrv';
import GatewayConnectionCtr from '../GatewayConnectionCtr';
import LocalFileCtr from '../LocalFileCtr';
import RemoteServerConfigCtr from '../RemoteServerConfigCtr';
import ShellCommandCtr from '../ShellCommandCtr';
// ─── Mocks ───
const { ipcMainHandleMock, MockGatewayClient } = vi.hoisted(() => {
const { EventEmitter } = require('node:events');
// Must be defined inside vi.hoisted so it's available when vi.mock factories run
class _MockGatewayClient extends EventEmitter {
static lastInstance: _MockGatewayClient | null = null;
static lastOptions: any = null;
connectionStatus = 'disconnected' as string;
currentDeviceId: string;
connect = vi.fn(async () => {
this.connectionStatus = 'connecting';
this.emit('status_changed', 'connecting');
});
disconnect = vi.fn(async () => {
this.connectionStatus = 'disconnected';
});
sendToolCallResponse = vi.fn();
constructor(options: any) {
super();
this.currentDeviceId = options.deviceId || 'mock-device-id';
_MockGatewayClient.lastInstance = this;
_MockGatewayClient.lastOptions = options;
}
// Test helpers
simulateConnected() {
this.connectionStatus = 'connected';
this.emit('status_changed', 'connected');
this.emit('connected');
}
simulateStatusChanged(status: string) {
this.connectionStatus = status;
this.emit('status_changed', status);
}
simulateToolCallRequest(apiName: string, args: object, requestId = 'req-1') {
this.emit('tool_call_request', {
requestId,
toolCall: {
apiName,
arguments: JSON.stringify(args),
identifier: 'test-tool',
},
type: 'tool_call_request',
});
}
simulateAuthExpired() {
this.emit('auth_expired');
}
simulateError(message: string) {
this.emit('error', new Error(message));
}
simulateReconnecting(delay: number) {
this.connectionStatus = 'reconnecting';
this.emit('status_changed', 'reconnecting');
this.emit('reconnecting', delay);
}
}
return {
MockGatewayClient: _MockGatewayClient,
ipcMainHandleMock: vi.fn(),
};
});
vi.mock('electron', () => ({
app: {
getPath: vi.fn((name: string) => `/mock/${name}`),
},
ipcMain: { handle: ipcMainHandleMock },
}));
vi.mock('@/utils/logger', () => ({
createLogger: () => ({
debug: vi.fn(),
error: vi.fn(),
info: vi.fn(),
verbose: vi.fn(),
warn: vi.fn(),
}),
}));
vi.mock('electron-is', () => ({
macOS: vi.fn(() => false),
windows: vi.fn(() => false),
linux: vi.fn(() => false),
}));
vi.mock('@/const/env', () => ({
OFFICIAL_CLOUD_SERVER: 'https://lobehub-cloud.com',
isMac: false,
isWindows: false,
isLinux: false,
isDev: false,
}));
vi.mock('node:crypto', () => ({
randomUUID: vi.fn(() => 'mock-device-uuid'),
}));
vi.mock('node:os', () => ({
default: { hostname: vi.fn(() => 'mock-hostname') },
}));
vi.mock('@lobechat/device-gateway-client', () => ({
GatewayClient: MockGatewayClient,
}));
// ─── Mock Controllers ───
const mockLocalFileCtr = {
handleEditFile: vi.fn().mockResolvedValue({ success: true }),
handleGlobFiles: vi.fn().mockResolvedValue({ files: [] }),
handleGrepContent: vi.fn().mockResolvedValue({ matches: [] }),
handleLocalFilesSearch: vi.fn().mockResolvedValue([]),
handleMoveFiles: vi.fn().mockResolvedValue([]),
handleRenameFile: vi.fn().mockResolvedValue({ newPath: '/mock/renamed.txt', success: true }),
handleWriteFile: vi.fn().mockResolvedValue({ success: true }),
listLocalFiles: vi.fn().mockResolvedValue([]),
readFile: vi.fn().mockResolvedValue({
charCount: 12,
content: 'file content',
createdTime: new Date('2024-01-01'),
filename: 'test.txt',
fileType: '.txt',
lineCount: 1,
loc: [1, 1] as [number, number],
modifiedTime: new Date('2024-01-01'),
totalCharCount: 12,
totalLineCount: 1,
}),
} as unknown as LocalFileCtr;
const mockShellCommandCtr = {
handleGetCommandOutput: vi.fn().mockResolvedValue({ output: '' }),
handleKillCommand: vi.fn().mockResolvedValue({ success: true }),
handleRunCommand: vi.fn().mockResolvedValue({ success: true, stdout: '' }),
} as unknown as ShellCommandCtr;
const mockRemoteServerConfigCtr = {
getAccessToken: vi.fn().mockResolvedValue('mock-access-token'),
isRemoteServerConfigured: vi.fn().mockResolvedValue(true),
refreshAccessToken: vi.fn().mockResolvedValue({ success: true }),
} as unknown as RemoteServerConfigCtr;
const mockBroadcast = vi.fn();
const mockStoreGet = vi.fn();
const mockStoreSet = vi.fn();
const mockApp = {
browserManager: { broadcastToAllWindows: mockBroadcast },
getController: vi.fn((Cls) => {
if (Cls === RemoteServerConfigCtr) return mockRemoteServerConfigCtr;
if (Cls === LocalFileCtr) return mockLocalFileCtr;
if (Cls === ShellCommandCtr) return mockShellCommandCtr;
return null;
}),
getService: vi.fn((Cls) => {
if (Cls === GatewayConnectionService) return mockGatewayConnectionSrv;
return null;
}),
storeManager: { get: mockStoreGet, set: mockStoreSet },
} as unknown as App;
// Lazily initialized — created in beforeEach so it uses the current mockApp
let mockGatewayConnectionSrv: GatewayConnectionService;
// ─── Test Suite ───
describe('GatewayConnectionCtr', () => {
let ctr: GatewayConnectionCtr;
beforeEach(() => {
vi.clearAllMocks();
vi.useFakeTimers();
MockGatewayClient.lastInstance = null;
MockGatewayClient.lastOptions = null;
mockStoreGet.mockImplementation((key: string) => {
if (key === 'gatewayEnabled') return true;
return undefined;
});
mockGatewayConnectionSrv = new GatewayConnectionService(mockApp);
ctr = new GatewayConnectionCtr(mockApp);
});
afterEach(() => {
ctr.disconnect();
vi.useRealTimers();
});
// ─── Connection ───
describe('connect', () => {
it('should create GatewayClient with correct options', async () => {
mockStoreGet.mockImplementation((key: string) => {
if (key === 'gatewayEnabled') return true;
if (key === 'gatewayDeviceId') return 'stored-device-id';
if (key === 'gatewayUrl') return undefined;
return undefined;
});
ctr = new GatewayConnectionCtr(mockApp);
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
const options = MockGatewayClient.lastOptions;
expect(options).not.toBeNull();
expect(options.token).toBe('mock-access-token');
expect(options.deviceId).toBe('stored-device-id');
expect(options.gatewayUrl).toBe('https://device-gateway.lobehub.com');
expect(options.logger).toBeDefined();
});
it('should use custom gateway URL from store when set', async () => {
mockStoreGet.mockImplementation((key: string) => {
if (key === 'gatewayEnabled') return true;
if (key === 'gatewayUrl') return 'http://localhost:8787';
return undefined;
});
ctr = new GatewayConnectionCtr(mockApp);
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
expect(MockGatewayClient.lastOptions.gatewayUrl).toBe('http://localhost:8787');
});
it('should return success:false when no access token', async () => {
// Prevent auto-connect, then set up providers manually
vi.mocked(mockRemoteServerConfigCtr.isRemoteServerConfigured).mockResolvedValueOnce(false);
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
vi.mocked(mockRemoteServerConfigCtr.getAccessToken).mockResolvedValueOnce(null);
const result = await ctr.connect();
expect(result).toEqual({ error: 'No access token available', success: false });
expect(MockGatewayClient.lastInstance).toBeNull();
});
it('should persist gatewayEnabled=true on connect', async () => {
vi.mocked(mockRemoteServerConfigCtr.isRemoteServerConfigured).mockResolvedValueOnce(false);
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
mockStoreSet.mockClear();
await ctr.connect();
expect(mockStoreSet).toHaveBeenCalledWith('gatewayEnabled', true);
});
it('should no-op when already connected', async () => {
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
const firstClient = MockGatewayClient.lastInstance;
firstClient!.simulateConnected();
const result = await ctr.connect();
expect(result).toEqual({ success: true });
// No new client created
expect(MockGatewayClient.lastInstance).toBe(firstClient);
});
it('should broadcast status changes: disconnected → connecting → connected', async () => {
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
expect(mockBroadcast).toHaveBeenCalledWith('gatewayConnectionStatusChanged', {
status: 'connecting',
});
MockGatewayClient.lastInstance!.simulateConnected();
expect(mockBroadcast).toHaveBeenCalledWith('gatewayConnectionStatusChanged', {
status: 'connected',
});
});
});
// ─── Disconnect ───
describe('disconnect', () => {
it('should disconnect client and set status to disconnected', async () => {
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
const client = MockGatewayClient.lastInstance!;
client.simulateConnected();
mockBroadcast.mockClear();
await ctr.disconnect();
expect(client.disconnect).toHaveBeenCalled();
expect(mockBroadcast).toHaveBeenCalledWith('gatewayConnectionStatusChanged', {
status: 'disconnected',
});
});
it('should persist gatewayEnabled=false on disconnect', async () => {
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
MockGatewayClient.lastInstance!.simulateConnected();
mockStoreSet.mockClear();
await ctr.disconnect();
expect(mockStoreSet).toHaveBeenCalledWith('gatewayEnabled', false);
});
it('should not trigger reconnect after intentional disconnect', async () => {
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
const client = MockGatewayClient.lastInstance!;
client.simulateConnected();
await ctr.disconnect();
mockBroadcast.mockClear();
// Advance timers — no reconnect should happen
await vi.advanceTimersByTimeAsync(60_000);
expect(mockBroadcast).not.toHaveBeenCalledWith('gatewayConnectionStatusChanged', {
status: 'reconnecting',
});
});
});
// ─── Auto-Connect ───
describe('afterAppReady (auto-connect)', () => {
it('should auto-connect when server is configured and token exists', async () => {
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
expect(MockGatewayClient.lastInstance).not.toBeNull();
expect(MockGatewayClient.lastInstance!.connect).toHaveBeenCalled();
});
it('should skip auto-connect when gatewayEnabled is false', async () => {
mockStoreGet.mockImplementation((key: string) => {
if (key === 'gatewayEnabled') return false;
return undefined;
});
ctr = new GatewayConnectionCtr(mockApp);
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
expect(MockGatewayClient.lastInstance).toBeNull();
});
it('should skip auto-connect when remote server not configured', async () => {
vi.mocked(mockRemoteServerConfigCtr.isRemoteServerConfigured).mockResolvedValueOnce(false);
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
expect(MockGatewayClient.lastInstance).toBeNull();
});
it('should skip auto-connect when no access token', async () => {
vi.mocked(mockRemoteServerConfigCtr.getAccessToken).mockResolvedValueOnce(null);
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
expect(MockGatewayClient.lastInstance).toBeNull();
});
it('should create device ID on first launch and persist it', () => {
mockStoreGet.mockReturnValue(undefined);
ctr.afterAppReady();
expect(mockStoreSet).toHaveBeenCalledWith('gatewayDeviceId', 'mock-device-uuid');
});
it('should reuse persisted device ID', () => {
mockStoreGet.mockImplementation((key: string) => {
if (key === 'gatewayEnabled') return true;
if (key === 'gatewayDeviceId') return 'existing-id';
return undefined;
});
ctr = new GatewayConnectionCtr(mockApp);
ctr.afterAppReady();
expect(mockStoreSet).not.toHaveBeenCalledWith('gatewayDeviceId', expect.anything());
});
});
// ─── Reconnection ───
describe('reconnection', () => {
it('should broadcast reconnecting status when client emits reconnecting', async () => {
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
const client = MockGatewayClient.lastInstance!;
client.simulateConnected();
mockBroadcast.mockClear();
client.simulateReconnecting(1000);
expect(mockBroadcast).toHaveBeenCalledWith('gatewayConnectionStatusChanged', {
status: 'reconnecting',
});
});
});
// ─── Tool Call Routing ───
describe('tool call routing', () => {
async function connectAndOpen() {
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
const client = MockGatewayClient.lastInstance!;
client.simulateConnected();
return client;
}
it.each([
['readLocalFile', 'readFile', mockLocalFileCtr],
['listLocalFiles', 'listLocalFiles', mockLocalFileCtr],
['moveLocalFiles', 'handleMoveFiles', mockLocalFileCtr],
['renameLocalFile', 'handleRenameFile', mockLocalFileCtr],
['searchLocalFiles', 'handleLocalFilesSearch', mockLocalFileCtr],
['writeLocalFile', 'handleWriteFile', mockLocalFileCtr],
['editLocalFile', 'handleEditFile', mockLocalFileCtr],
['globLocalFiles', 'handleGlobFiles', mockLocalFileCtr],
['grepContent', 'handleGrepContent', mockLocalFileCtr],
['runCommand', 'handleRunCommand', mockShellCommandCtr],
['getCommandOutput', 'handleGetCommandOutput', mockShellCommandCtr],
['killCommand', 'handleKillCommand', mockShellCommandCtr],
] as const)('should route %s to %s', async (apiName, methodName, controller) => {
const client = await connectAndOpen();
const args = { test: 'arg' };
client.simulateToolCallRequest(apiName, args);
await vi.advanceTimersByTimeAsync(0);
expect((controller as any)[methodName]).toHaveBeenCalledWith(args);
});
it('should send tool_call_response with success result', async () => {
vi.mocked(mockLocalFileCtr.readFile).mockResolvedValueOnce({
charCount: 5,
content: 'hello',
createdTime: new Date('2024-01-01'),
filename: 'a.txt',
fileType: '.txt',
lineCount: 1,
loc: [1, 1] as [number, number],
modifiedTime: new Date('2024-01-01'),
totalCharCount: 5,
totalLineCount: 1,
});
const client = await connectAndOpen();
client.simulateToolCallRequest('readLocalFile', { path: '/a.txt' }, 'req-42');
await vi.advanceTimersByTimeAsync(0);
expect(client.sendToolCallResponse).toHaveBeenCalledWith({
requestId: 'req-42',
result: {
content: JSON.stringify({
charCount: 5,
content: 'hello',
createdTime: new Date('2024-01-01'),
filename: 'a.txt',
fileType: '.txt',
lineCount: 1,
loc: [1, 1],
modifiedTime: new Date('2024-01-01'),
totalCharCount: 5,
totalLineCount: 1,
}),
success: true,
},
});
});
it('should send tool_call_response with error on failure', async () => {
vi.mocked(mockLocalFileCtr.readFile).mockRejectedValueOnce(new Error('File not found'));
const client = await connectAndOpen();
client.simulateToolCallRequest('readLocalFile', { path: '/missing' }, 'req-err');
await vi.advanceTimersByTimeAsync(0);
expect(client.sendToolCallResponse).toHaveBeenCalledWith({
requestId: 'req-err',
result: {
content: 'File not found',
error: 'File not found',
success: false,
},
});
});
it('should send error for unknown apiName', async () => {
const client = await connectAndOpen();
client.simulateToolCallRequest('unknownApi', {}, 'req-unknown');
await vi.advanceTimersByTimeAsync(0);
const errorMsg =
'Tool "unknownApi" is not available on this device. It may not be supported in the current desktop version. Please skip this tool and try alternative approaches.';
expect(client.sendToolCallResponse).toHaveBeenCalledWith({
requestId: 'req-unknown',
result: {
content: errorMsg,
error: errorMsg,
success: false,
},
});
});
});
// ─── Auth Expired ───
describe('auth_expired handling', () => {
it('should refresh token and reconnect on auth_expired', async () => {
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
const client1 = MockGatewayClient.lastInstance!;
client1.simulateConnected();
client1.simulateAuthExpired();
await vi.advanceTimersByTimeAsync(0);
expect(mockRemoteServerConfigCtr.refreshAccessToken).toHaveBeenCalled();
// Should have created a new GatewayClient for reconnection
expect(MockGatewayClient.lastInstance).not.toBe(client1);
expect(MockGatewayClient.lastInstance!.connect).toHaveBeenCalled();
});
it('should set status to disconnected when token refresh fails', async () => {
vi.mocked(mockRemoteServerConfigCtr.refreshAccessToken).mockResolvedValueOnce({
error: 'invalid_grant',
success: false,
});
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
const client = MockGatewayClient.lastInstance!;
client.simulateConnected();
mockBroadcast.mockClear();
client.simulateAuthExpired();
await vi.advanceTimersByTimeAsync(0);
expect(mockBroadcast).toHaveBeenCalledWith('gatewayConnectionStatusChanged', {
status: 'disconnected',
});
});
});
// ─── IPC Methods ───
describe('getConnectionStatus', () => {
it('should return current status', async () => {
expect(await ctr.getConnectionStatus()).toEqual({ status: 'disconnected' });
ctr.afterAppReady();
await vi.advanceTimersByTimeAsync(0);
expect(await ctr.getConnectionStatus()).toEqual({ status: 'connecting' });
MockGatewayClient.lastInstance!.simulateConnected();
expect(await ctr.getConnectionStatus()).toEqual({ status: 'connected' });
});
});
describe('getDeviceInfo', () => {
it('should return device information', async () => {
mockStoreGet.mockImplementation((key: string) => {
if (key === 'gatewayEnabled') return true;
if (key === 'gatewayDeviceId') return 'my-device';
return undefined;
});
ctr = new GatewayConnectionCtr(mockApp);
ctr.afterAppReady();
const info = await ctr.getDeviceInfo();
expect(info).toEqual({
description: '',
deviceId: 'my-device',
hostname: 'mock-hostname',
name: 'mock-hostname',
platform: process.platform,
});
});
});
});
@@ -45,6 +45,7 @@ vi.mock('node:fs/promises', () => ({
mkdir: vi.fn(),
readFile: vi.fn(),
readdir: vi.fn(),
realpath: vi.fn(),
rename: vi.fn(),
rm: vi.fn(),
stat: vi.fn(),
@@ -301,6 +302,46 @@ describe('LocalFileCtr', () => {
});
});
describe('auditSafePaths', () => {
it('should treat real temporary paths as safe', async () => {
vi.mocked(mockFsPromises.access).mockResolvedValue(undefined);
vi.mocked(mockFsPromises.realpath).mockImplementation(async (targetPath: string) => {
if (targetPath === '/tmp') return '/private/tmp';
if (targetPath === '/var/tmp') return '/private/var/tmp';
if (targetPath === '/tmp/out') return '/private/tmp/out';
return targetPath;
});
const result = await localFileCtr.auditSafePaths({
paths: ['/tmp/out'],
resolveAgainstScope: '/Users/me/project',
});
expect(result).toEqual({ allSafe: true });
});
it('should reject safe-path candidates whose real target escapes the temporary roots', async () => {
vi.mocked(mockFsPromises.access).mockImplementation(async (targetPath: string) => {
if (targetPath === '/tmp/out/config') {
throw new Error('ENOENT');
}
});
vi.mocked(mockFsPromises.realpath).mockImplementation(async (targetPath: string) => {
if (targetPath === '/tmp') return '/private/tmp';
if (targetPath === '/var/tmp') return '/private/var/tmp';
if (targetPath === '/tmp/out') return '/Users/me/.ssh';
return targetPath;
});
const result = await localFileCtr.auditSafePaths({
paths: ['/tmp/out/config'],
resolveAgainstScope: '/Users/me/project',
});
expect(result).toEqual({ allSafe: false });
});
});
describe('handlePrepareSkillDirectory', () => {
it('should download and extract a skill zip into a local cache directory', async () => {
const zipped = zipSync({
@@ -47,8 +47,14 @@ const mockBrowserManager = {
broadcastToAllWindows: vi.fn(),
};
const mockGatewayConnectionSrv = {
disconnect: vi.fn().mockResolvedValue({ success: true }),
};
const mockApp = {
browserManager: mockBrowserManager,
getController: vi.fn(),
getService: vi.fn().mockReturnValue(mockGatewayConnectionSrv),
storeManager: mockStoreManager,
} as unknown as App;
@@ -294,6 +300,13 @@ describe('RemoteServerConfigCtr', () => {
const accessToken = await controller.getAccessToken();
expect(accessToken).toBeNull();
});
it('should disconnect gateway when tokens are cleared', async () => {
await controller.saveTokens('access', 'refresh', 3600);
await controller.clearTokens();
expect(mockGatewayConnectionSrv.disconnect).toHaveBeenCalled();
});
});
describe('getTokenExpiresAt', () => {
@@ -3,6 +3,7 @@ import type { CreateServicesResult, IpcServiceConstructor, MergeIpcService } fro
import AuthCtr from './AuthCtr';
import BrowserWindowsCtr from './BrowserWindowsCtr';
import DevtoolsCtr from './DevtoolsCtr';
import GatewayConnectionCtr from './GatewayConnectionCtr';
import LocalFileCtr from './LocalFileCtr';
import McpCtr from './McpCtr';
import McpInstallCtr from './McpInstallCtr';
@@ -23,6 +24,7 @@ export const controllerIpcConstructors = [
AuthCtr,
BrowserWindowsCtr,
DevtoolsCtr,
GatewayConnectionCtr,
LocalFileCtr,
McpCtr,
McpInstallCtr,
@@ -0,0 +1,317 @@
import { randomUUID } from 'node:crypto';
import os from 'node:os';
import type {
SystemInfoRequestMessage,
ToolCallRequestMessage,
} from '@lobechat/device-gateway-client';
import { GatewayClient } from '@lobechat/device-gateway-client';
import type { GatewayConnectionStatus } from '@lobechat/electron-client-ipc';
import { app } from 'electron';
import { createLogger } from '@/utils/logger';
import { ServiceModule } from './index';
const logger = createLogger('services:GatewayConnectionSrv');
const DEFAULT_GATEWAY_URL = 'https://device-gateway.lobehub.com';
interface ToolCallHandler {
(apiName: string, args: any): Promise<unknown>;
}
/**
* GatewayConnectionService
*
* Core business logic for managing WebSocket connection to the cloud device-gateway.
* Extracted from GatewayConnectionCtr so other controllers can reuse connect/disconnect.
*/
export default class GatewayConnectionService extends ServiceModule {
private client: GatewayClient | null = null;
private status: GatewayConnectionStatus = 'disconnected';
private deviceId: string | null = null;
private tokenProvider: (() => Promise<string | null>) | null = null;
private tokenRefresher: (() => Promise<{ error?: string; success: boolean }>) | null = null;
private toolCallHandler: ToolCallHandler | null = null;
// ─── Configuration ───
/**
* Set token provider function (to decouple from RemoteServerConfigCtr)
*/
setTokenProvider(provider: () => Promise<string | null>) {
this.tokenProvider = provider;
}
/**
* Set token refresher function (for auth_expired handling)
*/
setTokenRefresher(refresher: () => Promise<{ error?: string; success: boolean }>) {
this.tokenRefresher = refresher;
}
/**
* Set tool call handler (to route tool calls to LocalFileCtr/ShellCommandCtr)
*/
setToolCallHandler(handler: ToolCallHandler) {
this.toolCallHandler = handler;
}
// ─── Device ID ───
loadOrCreateDeviceId() {
const stored = this.app.storeManager.get('gatewayDeviceId') as string | undefined;
if (stored) {
this.deviceId = stored;
} else {
this.deviceId = randomUUID();
this.app.storeManager.set('gatewayDeviceId', this.deviceId);
}
logger.debug(`Device ID: ${this.deviceId}`);
}
getDeviceId(): string {
return this.deviceId || 'unknown';
}
// ─── Connection Status ───
getStatus(): GatewayConnectionStatus {
return this.status;
}
getDeviceInfo() {
return {
description: this.getDeviceDescription(),
deviceId: this.getDeviceId(),
hostname: os.hostname(),
name: this.getDeviceName(),
platform: process.platform,
};
}
// ─── Device Name & Description ───
getDeviceName(): string {
return (this.app.storeManager.get('gatewayDeviceName') as string) || os.hostname();
}
setDeviceName(name: string) {
this.app.storeManager.set('gatewayDeviceName', name);
}
getDeviceDescription(): string {
return (this.app.storeManager.get('gatewayDeviceDescription') as string) || '';
}
setDeviceDescription(description: string) {
this.app.storeManager.set('gatewayDeviceDescription', description);
}
// ─── Connection Logic ───
async connect(): Promise<{ error?: string; success: boolean }> {
if (this.status === 'connected' || this.status === 'connecting') {
return { success: true };
}
return this.doConnect();
}
async disconnect(): Promise<{ success: boolean }> {
if (this.client) {
await this.client.disconnect();
this.client = null;
}
this.setStatus('disconnected');
return { success: true };
}
private async doConnect(): Promise<{ error?: string; success: boolean }> {
// Clean up any existing client
if (this.client) {
await this.client.disconnect();
this.client = null;
}
if (!this.tokenProvider) {
logger.warn('Cannot connect: no token provider configured');
return { error: 'No token provider configured', success: false };
}
const token = await this.tokenProvider();
if (!token) {
logger.warn('Cannot connect: no access token');
return { error: 'No access token available', success: false };
}
const gatewayUrl = this.getGatewayUrl();
const userId = this.extractUserIdFromToken(token);
logger.info(`Connecting to device gateway: ${gatewayUrl}, userId: ${userId || 'unknown'}`);
const client = new GatewayClient({
deviceId: this.getDeviceId(),
gatewayUrl,
logger,
token,
userId: userId || undefined,
});
this.setupClientEvents(client);
this.client = client;
await client.connect();
return { success: true };
}
private setupClientEvents(client: GatewayClient) {
client.on('status_changed', (status) => {
this.setStatus(status);
});
client.on('tool_call_request', (request) => {
this.handleToolCallRequest(request, client);
});
client.on('system_info_request', (request) => {
this.handleSystemInfoRequest(client, request);
});
client.on('auth_expired', () => {
logger.warn('Received auth_expired, will reconnect with refreshed token');
this.handleAuthExpired();
});
client.on('error', (error) => {
logger.error('WebSocket error:', error.message);
});
}
// ─── Auth Expired Handling ───
private async handleAuthExpired() {
// Disconnect the current client
if (this.client) {
await this.client.disconnect();
this.client = null;
}
if (!this.tokenRefresher) {
logger.error('No token refresher configured, cannot handle auth_expired');
this.setStatus('disconnected');
return;
}
logger.info('Attempting token refresh before reconnect');
const result = await this.tokenRefresher();
if (result.success) {
logger.info('Token refreshed, reconnecting');
await this.doConnect();
} else {
logger.error('Token refresh failed:', result.error);
this.setStatus('disconnected');
}
}
// ─── System Info ───
private handleSystemInfoRequest(client: GatewayClient, request: SystemInfoRequestMessage) {
logger.info(`Received system_info_request: requestId=${request.requestId}`);
client.sendSystemInfoResponse({
requestId: request.requestId,
result: {
success: true,
systemInfo: {
arch: os.arch(),
desktopPath: app.getPath('desktop'),
documentsPath: app.getPath('documents'),
downloadsPath: app.getPath('downloads'),
homePath: app.getPath('home'),
musicPath: app.getPath('music'),
picturesPath: app.getPath('pictures'),
userDataPath: app.getPath('userData'),
videosPath: app.getPath('videos'),
workingDirectory: process.cwd(),
},
},
});
}
// ─── Tool Call Routing ───
private handleToolCallRequest = async (
request: ToolCallRequestMessage,
client: GatewayClient,
) => {
const { requestId, toolCall } = request;
const { apiName, arguments: argsStr } = toolCall;
logger.info(`Received tool call: apiName=${apiName}, requestId=${requestId}`);
try {
if (!this.toolCallHandler) {
throw new Error('No tool call handler configured');
}
const args = JSON.parse(argsStr);
const result = await this.toolCallHandler(apiName, args);
client.sendToolCallResponse({
requestId,
result: {
content: typeof result === 'string' ? result : JSON.stringify(result),
success: true,
},
});
} catch (error) {
const errorMsg = error instanceof Error ? error.message : String(error);
logger.error(`Tool call failed: apiName=${apiName}, error=${errorMsg}`);
client.sendToolCallResponse({
requestId,
result: {
content: errorMsg,
error: errorMsg,
success: false,
},
});
}
};
// ─── Status Broadcasting ───
private setStatus(status: GatewayConnectionStatus) {
if (this.status === status) return;
logger.info(`Connection status: ${this.status}${status}`);
this.status = status;
this.app.browserManager.broadcastToAllWindows('gatewayConnectionStatusChanged', { status });
}
// ─── Gateway URL ───
private getGatewayUrl(): string {
return this.app.storeManager.get('gatewayUrl') || DEFAULT_GATEWAY_URL;
}
// ─── Token Helpers ───
/**
* Extract userId (sub claim) from JWT without verification.
* The token will be verified server-side; we just need the userId for routing.
*/
private extractUserIdFromToken(token: string): string | null {
try {
const parts = token.split('.');
if (parts.length !== 3) return null;
const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf-8'));
return payload.sub || null;
} catch {
logger.warn('Failed to extract userId from JWT token');
return null;
}
}
}
+5
View File
@@ -12,6 +12,11 @@ export interface ElectronMainStore {
lastRefreshAt?: number;
refreshToken?: string;
};
gatewayDeviceDescription: string;
gatewayDeviceId: string;
gatewayDeviceName: string;
gatewayEnabled: boolean;
gatewayUrl: string;
locale: string;
networkProxy: NetworkProxySettings;
shortcuts: Record<string, string>;
+17 -16
View File
@@ -1,7 +1,7 @@
import { DurableObject } from 'cloudflare:workers';
import { Hono } from 'hono';
import { verifyDesktopToken } from './auth';
import { resolveSocketAuth, verifyApiKeyToken, verifyDesktopToken } from './auth';
import type { DeviceAttachment, Env } from './types';
const AUTH_TIMEOUT = 10_000; // 10s to authenticate after connect
@@ -58,24 +58,25 @@ export class DeviceGatewayDO extends DurableObject<Env> {
if (att.authenticated) return; // Already authenticated, ignore
try {
const token = data.token as string;
if (!token) throw new Error('Missing token');
const token = data.token as string | undefined;
const tokenType = data.tokenType as 'apiKey' | 'jwt' | 'serviceToken' | undefined;
const serverUrl = data.serverUrl as string | undefined;
const storedUserId = await this.ctx.storage.get<string>('_userId');
let verifiedUserId: string;
if (token === this.env.SERVICE_TOKEN) {
// Service token auth (for CLI debugging)
const storedUserId = await this.ctx.storage.get<string>('_userId');
if (!storedUserId) throw new Error('Missing userId');
verifiedUserId = storedUserId;
} else {
// JWT auth (normal desktop flow)
const result = await verifyDesktopToken(this.env, token);
verifiedUserId = result.userId;
}
const verifiedUserId = await resolveSocketAuth({
serverUrl,
serviceToken: this.env.SERVICE_TOKEN,
storedUserId,
token,
tokenType,
verifyApiKey: verifyApiKeyToken,
verifyJwt: async (jwt) => {
const result = await verifyDesktopToken(this.env, jwt);
return { userId: result.userId };
},
});
// Verify userId matches the DO routing
const storedUserId = await this.ctx.storage.get<string>('_userId');
if (storedUserId && verifiedUserId !== storedUserId) {
throw new Error('userId mismatch');
}
+96
View File
@@ -0,0 +1,96 @@
import { describe, expect, it, vi } from 'vitest';
import { resolveSocketAuth } from './auth';
describe('resolveSocketAuth', () => {
it('rejects missing token', async () => {
const verifyApiKey = vi.fn();
const verifyJwt = vi.fn();
await expect(
resolveSocketAuth({
serviceToken: 'service-secret',
storedUserId: 'user-123',
verifyApiKey,
verifyJwt,
}),
).rejects.toThrow('Missing token');
expect(verifyApiKey).not.toHaveBeenCalled();
expect(verifyJwt).not.toHaveBeenCalled();
});
it('rejects the real service token when storedUserId is missing', async () => {
const verifyApiKey = vi.fn();
const verifyJwt = vi.fn();
await expect(
resolveSocketAuth({
serviceToken: 'service-secret',
token: 'service-secret',
tokenType: 'serviceToken',
verifyApiKey,
verifyJwt,
}),
).rejects.toThrow('Missing userId');
expect(verifyApiKey).not.toHaveBeenCalled();
expect(verifyJwt).not.toHaveBeenCalled();
});
it('rejects clients that only self-declare serviceToken mode', async () => {
const verifyApiKey = vi.fn();
const verifyJwt = vi.fn().mockRejectedValue(new Error('invalid jwt'));
await expect(
resolveSocketAuth({
serviceToken: 'service-secret',
storedUserId: 'user-123',
token: 'attacker-token',
tokenType: 'serviceToken',
verifyApiKey,
verifyJwt,
}),
).rejects.toThrow('invalid jwt');
expect(verifyApiKey).not.toHaveBeenCalled();
expect(verifyJwt).toHaveBeenCalledWith('attacker-token');
});
it('treats a forged serviceToken claim with a valid JWT as JWT auth', async () => {
const verifyApiKey = vi.fn();
const verifyJwt = vi.fn().mockResolvedValue({ userId: 'user-123' });
await expect(
resolveSocketAuth({
serviceToken: 'service-secret',
storedUserId: 'user-123',
token: 'valid-jwt',
tokenType: 'serviceToken',
verifyApiKey,
verifyJwt,
}),
).resolves.toBe('user-123');
expect(verifyApiKey).not.toHaveBeenCalled();
expect(verifyJwt).toHaveBeenCalledWith('valid-jwt');
});
it('accepts the real service token', async () => {
const verifyApiKey = vi.fn();
const verifyJwt = vi.fn();
await expect(
resolveSocketAuth({
serviceToken: 'service-secret',
storedUserId: 'user-123',
token: 'service-secret',
tokenType: 'serviceToken',
verifyApiKey,
verifyJwt,
}),
).resolves.toBe('user-123');
expect(verifyApiKey).not.toHaveBeenCalled();
expect(verifyJwt).not.toHaveBeenCalled();
});
});
+74
View File
@@ -4,6 +4,26 @@ import type { Env } from './types';
let cachedKey: CryptoKey | null = null;
interface CurrentUserResponse {
data?: {
id?: string;
userId?: string;
};
error?: string;
message?: string;
success?: boolean;
}
export interface ResolveSocketAuthOptions {
serverUrl?: string;
serviceToken: string;
storedUserId?: string;
token?: string;
tokenType?: 'apiKey' | 'jwt' | 'serviceToken';
verifyApiKey: (serverUrl: string, token: string) => Promise<{ userId: string }>;
verifyJwt: (token: string) => Promise<{ userId: string }>;
}
async function getPublicKey(env: Env): Promise<CryptoKey> {
if (cachedKey) return cachedKey;
@@ -34,3 +54,57 @@ export async function verifyDesktopToken(
userId: payload.sub,
};
}
export async function verifyApiKeyToken(
serverUrl: string,
token: string,
): Promise<{ userId: string }> {
const normalizedServerUrl = new URL(serverUrl).toString().replace(/\/$/, '');
const response = await fetch(`${normalizedServerUrl}/api/v1/users/me`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
let body: CurrentUserResponse | undefined;
try {
body = (await response.json()) as CurrentUserResponse;
} catch {
throw new Error(`Failed to parse response from ${normalizedServerUrl}/api/v1/users/me.`);
}
if (!response.ok || body?.success === false) {
throw new Error(
body?.error || body?.message || `Request failed with status ${response.status}.`,
);
}
const userId = body?.data?.id || body?.data?.userId;
if (!userId) {
throw new Error('Current user response did not include a user id.');
}
return { userId };
}
export async function resolveSocketAuth(options: ResolveSocketAuthOptions): Promise<string> {
const { serverUrl, serviceToken, storedUserId, token, tokenType, verifyApiKey, verifyJwt } =
options;
if (!token) throw new Error('Missing token');
if (tokenType === 'apiKey') {
if (!serverUrl) throw new Error('Missing serverUrl');
const result = await verifyApiKey(serverUrl, token);
return result.userId;
}
if (token === serviceToken) {
if (!storedUserId) throw new Error('Missing userId');
return storedUserId;
}
const result = await verifyJwt(token);
return result.userId;
}
+2
View File
@@ -20,7 +20,9 @@ export interface DeviceAttachment {
// Desktop → CF
export interface AuthMessage {
serverUrl?: string;
token: string;
tokenType?: 'apiKey' | 'jwt' | 'serviceToken';
type: 'auth';
}
+15
View File
@@ -1,4 +1,19 @@
[
{
"children": {
"improvements": ["add agent task system database schema."]
},
"date": "2026-03-26",
"version": "2.1.45"
},
{
"children": {
"fixes": ["misc UI/UX improvements and bug fixes."],
"improvements": ["add image/video switch."]
},
"date": "2026-03-20",
"version": "2.1.44"
},
{
"children": {
"improvements": [
+202 -1
View File
@@ -907,6 +907,46 @@ table nextauth_verificationtokens {
}
}
table notification_deliveries {
id uuid [pk, not null, default: `gen_random_uuid()`]
notification_id uuid [not null]
channel text [not null]
status text [not null]
provider_message_id text
failed_reason text
sent_at "timestamp with time zone"
created_at "timestamp with time zone" [not null, default: `now()`]
indexes {
notification_id [name: 'idx_deliveries_notification']
channel [name: 'idx_deliveries_channel']
status [name: 'idx_deliveries_status']
}
}
table notifications {
id uuid [pk, not null, default: `gen_random_uuid()`]
user_id text [not null]
category text [not null]
type text [not null]
title text [not null]
content text [not null]
dedupe_key text
action_url text
is_read boolean [not null, default: false]
is_archived boolean [not null, default: false]
created_at "timestamp with time zone" [not null, default: `now()`]
updated_at "timestamp with time zone" [not null, default: `now()`]
indexes {
user_id [name: 'idx_notifications_user']
(user_id, created_at) [name: 'idx_notifications_user_active']
user_id [name: 'idx_notifications_user_unread']
(user_id, dedupe_key) [name: 'idx_notifications_dedupe', unique]
(updated_at, created_at, id) [name: 'idx_notifications_archived_cleanup']
}
}
table oauth_handoffs {
id text [pk, not null]
client varchar(50) [not null]
@@ -1340,6 +1380,166 @@ table sessions {
}
}
table briefs {
id text [pk, not null]
user_id text [not null]
task_id text
cron_job_id text
topic_id text
agent_id text
type text [not null]
priority text [default: 'info']
title text [not null]
summary text [not null]
artifacts jsonb
actions jsonb
resolved_action text
resolved_comment text
read_at "timestamp with time zone"
resolved_at "timestamp with time zone"
created_at "timestamp with time zone" [not null, default: `now()`]
indexes {
user_id [name: 'briefs_user_id_idx']
task_id [name: 'briefs_task_id_idx']
cron_job_id [name: 'briefs_cron_job_id_idx']
agent_id [name: 'briefs_agent_id_idx']
type [name: 'briefs_type_idx']
priority [name: 'briefs_priority_idx']
(user_id, resolved_at) [name: 'briefs_unresolved_idx']
}
}
table task_comments {
id text [pk, not null]
task_id text [not null]
user_id text [not null]
author_user_id text
author_agent_id text
content text [not null]
editor_data jsonb
brief_id text
topic_id text
accessed_at "timestamp with time zone" [not null, default: `now()`]
created_at "timestamp with time zone" [not null, default: `now()`]
updated_at "timestamp with time zone" [not null, default: `now()`]
indexes {
task_id [name: 'task_comments_task_id_idx']
user_id [name: 'task_comments_user_id_idx']
author_user_id [name: 'task_comments_author_user_id_idx']
author_agent_id [name: 'task_comments_agent_id_idx']
brief_id [name: 'task_comments_brief_id_idx']
topic_id [name: 'task_comments_topic_id_idx']
}
}
table task_dependencies {
id uuid [pk, not null, default: `gen_random_uuid()`]
task_id text [not null]
depends_on_id text [not null]
user_id text [not null]
type text [not null, default: 'blocks']
condition jsonb
created_at "timestamp with time zone" [not null, default: `now()`]
indexes {
(task_id, depends_on_id) [name: 'task_deps_unique_idx', unique]
task_id [name: 'task_deps_task_id_idx']
depends_on_id [name: 'task_deps_depends_on_id_idx']
user_id [name: 'task_deps_user_id_idx']
}
}
table task_documents {
id uuid [pk, not null, default: `gen_random_uuid()`]
task_id text [not null]
document_id text [not null]
user_id text [not null]
pinned_by text [not null, default: 'agent']
created_at "timestamp with time zone" [not null, default: `now()`]
indexes {
(task_id, document_id) [name: 'task_docs_unique_idx', unique]
task_id [name: 'task_docs_task_id_idx']
document_id [name: 'task_docs_document_id_idx']
user_id [name: 'task_docs_user_id_idx']
}
}
table task_topics {
id uuid [pk, not null, default: `gen_random_uuid()`]
task_id text [not null]
topic_id text
user_id text [not null]
seq integer [not null]
operation_id text
status text [not null, default: 'running']
handoff jsonb
review_passed integer
review_score integer
review_scores jsonb
review_iteration integer
reviewed_at "timestamp with time zone"
accessed_at "timestamp with time zone" [not null, default: `now()`]
created_at "timestamp with time zone" [not null, default: `now()`]
updated_at "timestamp with time zone" [not null, default: `now()`]
indexes {
(task_id, topic_id) [name: 'task_topics_unique_idx', unique]
task_id [name: 'task_topics_task_id_idx']
topic_id [name: 'task_topics_topic_id_idx']
user_id [name: 'task_topics_user_id_idx']
(task_id, status) [name: 'task_topics_status_idx']
}
}
table tasks {
id text [pk, not null]
identifier text [not null]
seq integer [not null]
created_by_user_id text [not null]
created_by_agent_id text
assignee_user_id text
assignee_agent_id text
parent_task_id text
name text
description varchar(255)
instruction text [not null]
status text [not null, default: 'backlog']
priority integer [default: 0]
sort_order integer [default: 0]
heartbeat_interval integer [default: 300]
heartbeat_timeout integer
last_heartbeat_at "timestamp with time zone"
schedule_pattern text
schedule_timezone text [default: 'UTC']
total_topics integer [default: 0]
max_topics integer
current_topic_id text
context jsonb [default: `{}`]
config jsonb [default: `{}`]
error text
started_at "timestamp with time zone"
completed_at "timestamp with time zone"
accessed_at "timestamp with time zone" [not null, default: `now()`]
created_at "timestamp with time zone" [not null, default: `now()`]
updated_at "timestamp with time zone" [not null, default: `now()`]
indexes {
(identifier, created_by_user_id) [name: 'tasks_identifier_idx', unique]
created_by_user_id [name: 'tasks_created_by_user_id_idx']
created_by_agent_id [name: 'tasks_created_by_agent_id_idx']
assignee_user_id [name: 'tasks_assignee_user_id_idx']
assignee_agent_id [name: 'tasks_assignee_agent_id_idx']
parent_task_id [name: 'tasks_parent_task_id_idx']
status [name: 'tasks_status_idx']
priority [name: 'tasks_priority_idx']
(status, last_heartbeat_at) [name: 'tasks_heartbeat_idx']
}
}
table threads {
id text [pk, not null]
title text
@@ -1463,6 +1663,7 @@ table user_settings {
memory jsonb
tool jsonb
image jsonb
notification jsonb
}
table users {
@@ -1828,4 +2029,4 @@ ref: topic_documents.document_id > documents.id
ref: topic_documents.topic_id > topics.id
ref: topics.session_id - sessions.id
ref: topics.session_id - sessions.id
+1 -1
View File
@@ -88,7 +88,7 @@ async function createTestAgent(title: string = 'Test Agent'): Promise<string> {
// Given Steps
// ============================================
Given('用户在 Home 页面有一个 Agent', async function (this: CustomWorld) {
Given('用户在 Home 页面有一个 Agent', { timeout: 30_000 }, async function (this: CustomWorld) {
console.log(' 📍 Step: 在数据库中创建测试 Agent...');
const agentId = await createTestAgent('E2E Test Agent');
this.testContext.createdAgentId = agentId;
+1 -1
View File
@@ -166,7 +166,7 @@ async function clickNewPageButton(world: CustomWorld): Promise<void> {
// Given Steps
// ============================================
Given('用户在 Page 页面', async function (this: CustomWorld) {
Given('用户在 Page 页面', { timeout: 30_000 }, async function (this: CustomWorld) {
console.log(' 📍 Step: 导航到 Page 页面...');
await this.page.goto('/page');
await this.page.waitForLoadState('networkidle', { timeout: 15_000 });
+37 -1
View File
@@ -1,5 +1,6 @@
{
"channel.appSecret": "سر التطبيق",
"channel.appSecretHint": "سر التطبيق لتطبيق الروبوت الخاص بك. سيتم تشفيره وتخزينه بأمان.",
"channel.appSecretPlaceholder": "الصق سر التطبيق هنا",
"channel.applicationId": "معرف التطبيق / اسم المستخدم للبوت",
"channel.applicationIdHint": "معرف فريد لتطبيق البوت الخاص بك.",
@@ -9,14 +10,31 @@
"channel.botTokenHowToGet": "كيف تحصل عليه؟",
"channel.botTokenPlaceholderExisting": "الرمز مخفي لأسباب أمنية",
"channel.botTokenPlaceholderNew": "الصق رمز البوت هنا",
"channel.charLimit": "حد الأحرف",
"channel.charLimitHint": "الحد الأقصى لعدد الأحرف لكل رسالة",
"channel.connectFailed": "فشل اتصال الروبوت",
"channel.connectSuccess": "تم الاتصال بالروبوت بنجاح",
"channel.connecting": "جارٍ الاتصال...",
"channel.connectionConfig": "إعدادات الاتصال",
"channel.copied": "تم النسخ إلى الحافظة",
"channel.copy": "نسخ",
"channel.credentials": "بيانات الاعتماد",
"channel.debounceMs": "نافذة دمج الرسائل (مللي ثانية)",
"channel.debounceMsHint": "مدة الانتظار للرسائل الإضافية قبل إرسالها إلى الوكيل (مللي ثانية)",
"channel.deleteConfirm": "هل أنت متأكد أنك تريد إزالة هذه القناة؟",
"channel.deleteConfirmDesc": "سيؤدي هذا الإجراء إلى إزالة قناة الرسائل وتكوينها بشكل دائم. لا يمكن التراجع عن ذلك.",
"channel.devWebhookProxyUrl": "عنوان URL لنفق HTTPS",
"channel.devWebhookProxyUrlHint": "اختياري. عنوان URL لنفق HTTPS لإعادة توجيه طلبات الويب هوك إلى خادم التطوير المحلي.",
"channel.disabled": "معطل",
"channel.discord.description": "قم بتوصيل هذا المساعد بخادم Discord للدردشة في القنوات والرسائل المباشرة.",
"channel.dm": "الرسائل المباشرة",
"channel.dmEnabled": "تمكين الرسائل المباشرة",
"channel.dmEnabledHint": "السماح للروبوت بتلقي الرسائل المباشرة والرد عليها",
"channel.dmPolicy": "سياسة الرسائل المباشرة",
"channel.dmPolicyAllowlist": "القائمة المسموح بها",
"channel.dmPolicyDisabled": "معطل",
"channel.dmPolicyHint": "التحكم في من يمكنه إرسال الرسائل المباشرة إلى الروبوت",
"channel.dmPolicyOpen": "مفتوح",
"channel.documentation": "التوثيق",
"channel.enabled": "مفعّل",
"channel.encryptKey": "مفتاح التشفير",
@@ -26,6 +44,7 @@
"channel.endpointUrlHint": "يرجى نسخ هذا العنوان ولصقه في الحقل <bold>{{fieldName}}</bold> في بوابة مطوري {{name}}.",
"channel.feishu.description": "قم بتوصيل هذا المساعد بـ Feishu للدردشة الخاصة والجماعية.",
"channel.lark.description": "قم بتوصيل هذا المساعد بـ Lark للدردشة الخاصة والجماعية.",
"channel.openPlatform": "منصة مفتوحة",
"channel.platforms": "المنصات",
"channel.publicKey": "المفتاح العام",
"channel.publicKeyHint": "اختياري. يُستخدم للتحقق من طلبات التفاعل من Discord.",
@@ -42,6 +61,16 @@
"channel.secretToken": "رمز سر الويب هوك",
"channel.secretTokenHint": "اختياري. يُستخدم للتحقق من طلبات الويب هوك من Telegram.",
"channel.secretTokenPlaceholder": "السر الاختياري للتحقق من الويب هوك",
"channel.settings": "الإعدادات المتقدمة",
"channel.settingsResetConfirm": "هل أنت متأكد أنك تريد إعادة تعيين الإعدادات المتقدمة إلى الوضع الافتراضي؟",
"channel.settingsResetDefault": "إعادة إلى الوضع الافتراضي",
"channel.setupGuide": "دليل الإعداد",
"channel.showUsageStats": "عرض إحصائيات الاستخدام",
"channel.showUsageStatsHint": "عرض استخدام الرموز، التكلفة، وإحصائيات المدة في ردود الروبوت",
"channel.signingSecret": "سر التوقيع",
"channel.signingSecretHint": "يُستخدم للتحقق من طلبات الويب هوك.",
"channel.slack.appIdHint": "معرف تطبيق Slack الخاص بك من لوحة تحكم API Slack (يبدأ بـ A).",
"channel.slack.description": "قم بتوصيل هذا المساعد بـ Slack للمحادثات القنوية والرسائل المباشرة.",
"channel.telegram.description": "قم بتوصيل هذا المساعد بـ Telegram للدردشة الخاصة والجماعية.",
"channel.testConnection": "اختبار الاتصال",
"channel.testFailed": "فشل اختبار الاتصال",
@@ -50,5 +79,12 @@
"channel.validationError": "يرجى ملء معرف التطبيق والرمز",
"channel.verificationToken": "رمز التحقق",
"channel.verificationTokenHint": "اختياري. يُستخدم للتحقق من مصدر أحداث الويب هوك.",
"channel.verificationTokenPlaceholder": "الصق رمز التحقق هنا"
"channel.verificationTokenPlaceholder": "الصق رمز التحقق هنا",
"channel.wechat.description": "قم بتوصيل هذا المساعد بـ WeChat عبر iLink Bot للمحادثات الخاصة والجماعية.",
"channel.wechatQrExpired": "انتهت صلاحية رمز الاستجابة السريعة. يرجى التحديث للحصول على رمز جديد.",
"channel.wechatQrRefresh": "تحديث رمز الاستجابة السريعة",
"channel.wechatQrScaned": "تم مسح رمز الاستجابة السريعة. يرجى تأكيد تسجيل الدخول في WeChat.",
"channel.wechatQrWait": "افتح WeChat وقم بمسح رمز الاستجابة السريعة للاتصال.",
"channel.wechatScanTitle": "توصيل روبوت WeChat",
"channel.wechatScanToConnect": "مسح رمز الاستجابة السريعة للاتصال"
}
+3 -1
View File
@@ -397,7 +397,6 @@
"sync.status.unconnected": "فشل الاتصال",
"sync.title": "حالة المزامنة",
"sync.unconnected.tip": "فشل الاتصال بخادم الإشارة، ولا يمكن إنشاء قناة اتصال من نظير إلى نظير. يرجى التحقق من الشبكة والمحاولة مرة أخرى.",
"tab.aiImage": "الرسومات",
"tab.audio": "الصوت",
"tab.chat": "الدردشة",
"tab.community": "المجتمع",
@@ -405,6 +404,7 @@
"tab.eval": "مختبر التقييم",
"tab.files": "الملفات",
"tab.home": "الرئيسية",
"tab.image": "صورة",
"tab.knowledgeBase": "المكتبة",
"tab.marketplace": "السوق",
"tab.me": "أنا",
@@ -432,6 +432,7 @@
"userPanel.billing": "إدارة الفوترة",
"userPanel.cloud": "تشغيل {{name}}",
"userPanel.community": "المجتمع",
"userPanel.credits": "إدارة الرصيد",
"userPanel.data": "تخزين البيانات",
"userPanel.defaultNickname": "مستخدم المجتمع",
"userPanel.discord": "دعم المجتمع",
@@ -443,6 +444,7 @@
"userPanel.plans": "خطط الاشتراك",
"userPanel.profile": "الحساب",
"userPanel.setting": "الإعدادات",
"userPanel.upgradePlan": "ترقية الخطة",
"userPanel.usages": "إحصائيات الاستخدام",
"version": "الإصدار"
}
+5
View File
@@ -83,6 +83,11 @@
"preference.empty": "لا توجد ذكريات تفضيل متاحة",
"preference.source": "المصدر",
"preference.suggestions": "الإجراءات التي قد يتخذها الوكيل",
"purge.action": "حذف الكل",
"purge.confirm": "هل أنت متأكد أنك تريد حذف جميع الذكريات؟ سيؤدي ذلك إلى إزالة كل إدخال للذكريات بشكل دائم ولا يمكن التراجع عنه.",
"purge.error": "فشل في حذف الذكريات. يرجى المحاولة مرة أخرى.",
"purge.success": "تم حذف جميع الذكريات.",
"purge.title": "حذف جميع الذكريات",
"tab.activities": "الأنشطة",
"tab.contexts": "السياقات",
"tab.experiences": "التجارب",
+2
View File
@@ -231,6 +231,8 @@
"providerModels.item.modelConfig.extendParams.options.imageResolution.hint": "لنماذج توليد الصور من Gemini 3؛ يتحكم في دقة الصور المُولدة.",
"providerModels.item.modelConfig.extendParams.options.imageResolution2.hint": "لـ نماذج الصور Gemini 3.1 Flash؛ يتحكم في دقة الصور المُنشأة (يدعم 512 بكسل).",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken.hint": "لنماذج Claude وQwen3 وما شابهها؛ يتحكم في ميزانية الرموز المخصصة للاستدلال.",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken32k.hint": "لـ GLM-5 و GLM-4.7؛ يتحكم في ميزانية الرموز للتفكير (الحد الأقصى 32k).",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken80k.hint": "لسلسلة Qwen3؛ يتحكم في ميزانية الرموز للتفكير (الحد الأقصى 80k).",
"providerModels.item.modelConfig.extendParams.options.reasoningEffort.hint": "لنماذج OpenAI وغيرها من النماذج القادرة على الاستدلال؛ يتحكم في جهد الاستدلال.",
"providerModels.item.modelConfig.extendParams.options.textVerbosity.hint": "لسلسلة GPT-5+؛ يتحكم في تفصيل النص الناتج.",
"providerModels.item.modelConfig.extendParams.options.thinking.hint": "لبعض نماذج Doubao؛ يسمح للنموذج بتحديد ما إذا كان يجب التفكير بعمق.",
+43 -35
View File
@@ -53,7 +53,14 @@
"FLUX.1-Kontext-dev.description": "FLUX.1-Kontext-dev هو نموذج توليد وتحرير صور متعدد الوسائط من Black Forest Labs، مبني على بنية Rectified Flow Transformer ويحتوي على 12 مليار معامل. يركز على توليد الصور، إعادة بنائها، تحسينها أو تحريرها ضمن شروط سياقية محددة. يجمع بين قدرات التوليد القابلة للتحكم لنماذج الانتشار ونمذجة السياق باستخدام Transformer، ويدعم مخرجات عالية الجودة لمهام مثل inpainting، outpainting، وإعادة بناء المشاهد البصرية.",
"FLUX.1-Kontext-pro.description": "FLUX.1 Kontext [pro]",
"FLUX.1-dev.description": "FLUX.1-dev هو نموذج لغة متعدد الوسائط مفتوح المصدر من Black Forest Labs، محسن لمهام النص والصورة، ويجمع بين فهم وتوليد النصوص/الصور. مبني على نماذج LLM متقدمة (مثل Mistral-7B)، ويستخدم مشفر رؤية مصمم بعناية وضبط تعليمات متعدد المراحل لتمكين التنسيق متعدد الوسائط والاستدلال المعقد.",
"GLM-4.5-Air.description": "GLM-4.5-Air: إصدار خفيف الوزن للاستجابات السريعة.",
"GLM-4.5.description": "GLM-4.5: نموذج عالي الأداء للمنطق، البرمجة، ومهام الوكلاء.",
"GLM-4.6.description": "GLM-4.6: نموذج الجيل السابق.",
"GLM-4.7.description": "GLM-4.7 هو النموذج الرائد الأحدث من Zhipu، معزز لسيناريوهات البرمجة الوكيلية مع تحسين قدرات البرمجة، تخطيط المهام طويلة الأمد، والتعاون مع الأدوات.",
"GLM-5-Turbo.description": "GLM-5-Turbo: إصدار محسن من GLM-5 مع استدلال أسرع لمهام البرمجة.",
"GLM-5.description": "GLM-5 هو نموذج الأساس الرائد من الجيل التالي لـ Zhipu، مصمم خصيصًا للهندسة الوكيلية. يوفر إنتاجية موثوقة في هندسة الأنظمة المعقدة ومهام الوكلاء طويلة الأمد. في قدرات البرمجة والوكلاء، يحقق GLM-5 أداءً رائدًا بين النماذج مفتوحة المصدر.",
"Gryphe/MythoMax-L2-13b.description": "MythoMax-L2 (13B) هو نموذج مبتكر لمجالات متنوعة ومهام معقدة.",
"HY-Image-V3.0.description": "قدرات قوية لاستخراج الميزات من الصور الأصلية والحفاظ على التفاصيل، مما يوفر نسيجًا بصريًا أكثر ثراءً وينتج صورًا عالية الدقة ومتقنة ومناسبة للإنتاج.",
"HelloMeme.description": "HelloMeme هي أداة ذكاء اصطناعي لإنشاء الميمات، الصور المتحركة (GIFs)، أو مقاطع الفيديو القصيرة من الصور أو الحركات التي تقدمها. لا تتطلب مهارات رسم أو برمجة—فقط صورة مرجعية—لإنتاج محتوى ممتع وجذاب ومتناسق من حيث الأسلوب.",
"HiDream-E1-Full.description": "HiDream-E1-Full هو نموذج مفتوح المصدر لتحرير الصور متعدد الوسائط من HiDream.ai، يعتمد على بنية Diffusion Transformer المتقدمة وفهم قوي للغة (مدمج LLaMA 3.1-8B-Instruct). يدعم إنشاء الصور باستخدام اللغة الطبيعية، ونقل الأنماط، والتحرير المحلي، وإعادة الطلاء، مع فهم وتنفيذ ممتازين للنصوص والصور.",
"HiDream-I1-Full.description": "HiDream-I1 هو نموذج جديد مفتوح المصدر لإنشاء الصور تم إصداره من قبل HiDream. مع 17 مليار معلمة (Flux يحتوي على 12 مليار)، يمكنه تقديم جودة صور رائدة في الصناعة في ثوانٍ.",
@@ -81,17 +88,17 @@
"MiniMax-M1.description": "نموذج استدلال داخلي جديد بسلسلة تفكير تصل إلى 80K ومدخلات حتى 1M، يقدم أداءً مماثلاً لأفضل النماذج العالمية.",
"MiniMax-M2-Stable.description": "مصمم لتدفقات العمل البرمجية والوكلاء بكفاءة عالية، مع قدرة تزامن أعلى للاستخدام التجاري.",
"MiniMax-M2.1-Lightning.description": "قدرات برمجة متعددة اللغات قوية وتجربة برمجة مطورة بالكامل. أسرع وأكثر كفاءة.",
"MiniMax-M2.1-highspeed.description": "قدرات برمجة متعددة اللغات قوية مع استنتاج أسرع وأكثر كفاءة.",
"MiniMax-M2.1-highspeed.description": "قدرات برمجة متعددة اللغات قوية مع استدلال أسرع وأكثر كفاءة.",
"MiniMax-M2.1.description": "MiniMax-M2.1 هو نموذج مفتوح المصدر رائد من MiniMax، يركز على حل المهام الواقعية المعقدة. يتميز بقدرات برمجة متعددة اللغات والقدرة على أداء المهام المعقدة كوكلاء ذكي.",
"MiniMax-M2.5-Lightning.description": "M2.5 Lightning: نفس الأداء، أسرع وأكثر رشاقة (تقريباً 100 tps).",
"MiniMax-M2.5-highspeed.description": "نفس أداء M2.5 مع استنتاج أسرع بشكل ملحوظ.",
"MiniMax-M2.5-highspeed.description": "MiniMax M2.5 Highspeed: نفس أداء M2.5 مع استدلال أسرع.",
"MiniMax-M2.5.description": "أداء من الدرجة الأولى وفعالية تكلفة قصوى، يتعامل بسهولة مع المهام المعقدة (تقريباً 60 tps).",
"MiniMax-M2.7-highspeed.description": "نفس أداء M2.7 مع استدلال أسرع بشكل ملحوظ (~100 tps).",
"MiniMax-M2.7.description": "أول نموذج ذاتي التطور بأداء عالي المستوى في البرمجة والوكالة (~60 tps).",
"MiniMax-M2.description": "مصمم خصيصًا للبرمجة الفعالة وتدفقات عمل الوكلاء.",
"MiniMax-M2.7-highspeed.description": "MiniMax M2.7 Highspeed: نفس أداء M2.7 مع استدلال أسرع بشكل ملحوظ.",
"MiniMax-M2.7.description": "MiniMax M2.7: بداية رحلة التحسين الذاتي التكراري، قدرات هندسية واقعية رائدة.",
"MiniMax-M2.description": "MiniMax M2: نموذج الجيل السابق.",
"MiniMax-Text-01.description": "MiniMax-01 يقدم انتباهًا خطيًا واسع النطاق يتجاوز Transformers التقليدية، مع 456 مليار معامل و45.9 مليار مفعّلة في كل تمرير. يحقق أداءً من الدرجة الأولى ويدعم حتى 4 ملايين رمز سياقي (32× GPT-4o، 20× Claude-3.5-Sonnet).",
"MiniMaxAI/MiniMax-M1-80k.description": "MiniMax-M1 هو نموذج استدلال واسع النطاق بوزن مفتوح يستخدم انتباهًا هجينًا، يحتوي على 456 مليار معامل إجماليًا و~45.9 مليار مفعّلة لكل رمز. يدعم سياقًا يصل إلى 1M ويستخدم Flash Attention لتقليل FLOPs بنسبة 75% عند توليد 100K رمز مقارنة بـ DeepSeek R1. بهيكل MoE وتدريب RL هجين، يحقق أداءً رائدًا في الاستدلال طويل المدخلات ومهام هندسة البرمجيات الواقعية.",
"MiniMaxAI/MiniMax-M2.description": "MiniMax-M2 يعيد تعريف كفاءة الوكلاء. هو نموذج MoE مدمج وسريع وفعال من حيث التكلفة يحتوي على 230 مليار معامل إجماليًا و10 مليار مفعّلة، مصمم لمهام البرمجة والوكلاء من الدرجة الأولى مع الحفاظ على ذكاء عام قوي. مع 10 مليار معامل مفعّلة فقط، ينافس نماذج أكبر بكثير، مما يجعله مثاليًا للتطبيقات عالية الكفاءة.",
"MiniMaxAI/MiniMax-M1-80k.description": "MiniMax-M1 هو نموذج استدلال كبير مفتوح الأوزان مع 456 مليار معلمة إجمالية وحوالي 45.9 مليار نشطة لكل رمز. يدعم سياق 1 مليون بشكل طبيعي ويستخدم Flash Attention لتقليل FLOPs بنسبة 75% على توليد 100 ألف رمز مقارنة بـ DeepSeek R1. مع بنية MoE بالإضافة إلى CISPO وتدريب RL الهجين، يحقق أداءً رائدًا في الاستدلال طويل المدخلات ومهام الهندسة البرمجية الواقعية.",
"MiniMaxAI/MiniMax-M2.description": "MiniMax-M2 يعيد تعريف كفاءة الوكلاء. إنه نموذج MoE مضغوط وسريع وفعال من حيث التكلفة مع 230 مليار معلمة إجمالية و10 مليارات معلمة نشطة، مصمم لمهام البرمجة والوكلاء من الدرجة الأولى مع الحفاظ على ذكاء عام قوي. مع 10 مليارات معلمة نشطة فقط، ينافس النماذج الأكبر بكثير، مما يجعله مثاليًا للتطبيقات عالية الكفاءة.",
"Moonshot-Kimi-K2-Instruct.description": "يحتوي على 1 تريليون معامل إجماليًا و32 مليار مفعّلة. من بين النماذج غير المفكرة، يتصدر في المعرفة المتقدمة، الرياضيات، والبرمجة، وأقوى في مهام الوكلاء العامة. محسن لأعباء عمل الوكلاء، يمكنه اتخاذ إجراءات وليس فقط الإجابة على الأسئلة. الأفضل للمحادثات العامة الارتجالية وتجارب الوكلاء كنموذج يعمل بردود فعل دون تفكير طويل.",
"NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO.description": "Nous Hermes 2 - Mixtral 8x7B-DPO (46.7B) هو نموذج تعليمات عالي الدقة للحسابات المعقدة.",
"OmniConsistency.description": "تحسّن OmniConsistency التناسق الأسلوبي والتعميم في مهام تحويل الصور إلى صور من خلال إدخال محولات الانتشار واسعة النطاق (DiTs) وبيانات مزدوجة النمط، مما يمنع تدهور الأسلوب.",
@@ -105,14 +112,14 @@
"Phi-3.5-mini-instruct.description": "إصدار محدث من نموذج Phi-3-mini.",
"Phi-3.5-vision-instrust.description": "إصدار محدث من نموذج Phi-3-vision.",
"Pro/MiniMaxAI/MiniMax-M2.1.description": "MiniMax-M2.1 هو نموذج لغوي مفتوح المصدر ومتقدم، مُحسَّن لقدرات الوكلاء، ويتفوق في البرمجة، واستخدام الأدوات، واتباع التعليمات، والتخطيط طويل الأمد. يدعم النموذج تطوير البرمجيات متعددة اللغات وتنفيذ سير العمل المعقد متعدد الخطوات، وحقق نتيجة 74.0 على SWE-bench Verified، متفوقًا على Claude Sonnet 4.5 في السيناريوهات متعددة اللغات.",
"Pro/MiniMaxAI/MiniMax-M2.5.description": "MiniMax-M2.5 هو أحدث نموذج لغة كبير تم تطويره بواسطة MiniMax، تم تدريبه من خلال التعلم المعزز واسع النطاق عبر مئات الآلاف من البيئات المعقدة في العالم الحقيقي. يتميز بهيكل MoE مع 229 مليار معلمة، ويحقق أداءً رائدًا في الصناعة في مهام مثل البرمجة، واستدعاء أدوات الوكيل، والبحث، والسيناريوهات المكتبية.",
"Pro/MiniMaxAI/MiniMax-M2.5.description": "MiniMax-M2.5 هو أحدث نموذج لغة كبير تم تطويره بواسطة MiniMax، تم تدريبه من خلال التعلم المعزز واسع النطاق عبر مئات الآلاف من البيئات الواقعية المعقدة. يتميز ببنية MoE مع 229 مليار معلمة، ويحقق أداءً رائدًا في الصناعة في مهام مثل البرمجة، استدعاء أدوات الوكلاء، البحث، وسيناريوهات المكتب.",
"Pro/Qwen/Qwen2-7B-Instruct.description": "Qwen2-7B-Instruct هو نموذج لغوي كبير (LLM) موجه للتعليمات ضمن سلسلة Qwen2. يستخدم بنية Transformer مع SwiGLU، وانحياز QKV في الانتباه، وانتباه الاستعلامات المجمعة، ويعالج مدخلات كبيرة. يتميز بأداء قوي في فهم اللغة، التوليد، المهام متعددة اللغات، البرمجة، الرياضيات، والاستدلال، متفوقًا على معظم النماذج المفتوحة ومنافسًا للنماذج التجارية. يتفوق على Qwen1.5-7B-Chat في العديد من المعايير.",
"Pro/Qwen/Qwen2.5-7B-Instruct.description": "Qwen2.5-7B-Instruct هو جزء من أحدث سلسلة نماذج لغوية كبيرة من Alibaba Cloud. يقدم هذا النموذج ذو 7 مليارات معلمة تحسينات ملحوظة في البرمجة والرياضيات، ويدعم أكثر من 29 لغة، ويعزز اتباع التعليمات، وفهم البيانات المنظمة، وإنتاج المخرجات المنظمة (خصوصًا JSON).",
"Pro/Qwen/Qwen2.5-Coder-7B-Instruct.description": "Qwen2.5-Coder-7B-Instruct هو أحدث نموذج لغوي كبير من Alibaba Cloud يركز على البرمجة. مبني على Qwen2.5 ومدرب على 5.5 تريليون رمز، يعزز بشكل كبير توليد الشيفرة، الاستدلال، والإصلاح، مع الحفاظ على القوة في الرياضيات والقدرات العامة، مما يوفر أساسًا قويًا لوكلاء البرمجة.",
"Pro/Qwen/Qwen2.5-VL-7B-Instruct.description": "Qwen2.5-VL هو نموذج رؤية-لغة جديد من Qwen يتمتع بفهم بصري قوي. يحلل النصوص، الرسوم البيانية، والتخطيطات في الصور، ويفهم مقاطع الفيديو الطويلة والأحداث، ويدعم الاستدلال واستخدام الأدوات، وتحديد الكائنات عبر تنسيقات متعددة، وإنتاج مخرجات منظمة. يعزز فهم الفيديو من خلال تحسينات في الدقة الديناميكية ومعدل الإطارات، ويزيد من كفاءة مشفر الرؤية.",
"Pro/THUDM/GLM-4.1V-9B-Thinking.description": "GLM-4.1V-9B-Thinking هو نموذج رؤية-لغة مفتوح المصدر من Zhipu AI ومختبر KEG في جامعة تسينغهوا، مصمم للإدراك متعدد الوسائط المعقد. مبني على GLM-4-9B-0414، ويضيف استدلال سلسلة الأفكار والتعلم المعزز (RL) لتحسين الاستدلال عبر الوسائط والاستقرار بشكل كبير.",
"Pro/THUDM/glm-4-9b-chat.description": "GLM-4-9B-Chat هو النموذج المفتوح المصدر من سلسلة GLM-4 من Zhipu AI. يتميز بأداء قوي في الدلالات، الرياضيات، الاستدلال، البرمجة، والمعرفة. بالإضافة إلى المحادثة متعددة الأدوار، يدعم تصفح الويب، تنفيذ الشيفرة، استدعاء الأدوات المخصصة، والاستدلال على النصوص الطويلة. يدعم 26 لغة (بما في ذلك الصينية، الإنجليزية، اليابانية، الكورية، والألمانية). يحقق نتائج جيدة في AlignBench-v2، MT-Bench، MMLU، وC-Eval، ويدعم سياقًا يصل إلى 128 ألف رمز للاستخدام الأكاديمي والتجاري.",
"Pro/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "تم تقطير DeepSeek-R1-Distill-Qwen-7B من Qwen2.5-Math-7B وتم تحسينه باستخدام 800 ألف عينة مختارة من DeepSeek-R1. يتميز بأداء قوي، حيث يحقق 92.8٪ في MATH-500، و55.5٪ في AIME 2024، وتصنيف 1189 في CodeForces لنموذج بحجم 7 مليارات معلمة.",
"Pro/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "DeepSeek-R1-Distill-Qwen-7B مستخلص من Qwen2.5-Math-7B ومُحسن على 800 ألف عينة مختارة من DeepSeek-R1. يقدم أداءً قويًا، بنسبة 92.8% على MATH-500، و55.5% على AIME 2024، وتصنيف 1189 على CodeForces لنموذج 7B.",
"Pro/deepseek-ai/DeepSeek-R1.description": "DeepSeek-R1 هو نموذج استدلال مدفوع بالتعلم المعزز يقلل التكرار ويحسن قابلية القراءة. يستخدم بيانات بداية باردة قبل التعلم المعزز لتعزيز الاستدلال، ويضاهي OpenAI-o1 في مهام الرياضيات، البرمجة، والاستدلال، ويحقق نتائج أفضل من خلال تدريب دقيق.",
"Pro/deepseek-ai/DeepSeek-V3.1-Terminus.description": "DeepSeek-V3.1-Terminus هو إصدار محدث من نموذج V3.1، مصمم كنموذج وكيل هجين. يعالج المشكلات التي أبلغ عنها المستخدمون، ويحسن الاستقرار، وتناسق اللغة، ويقلل من الخلط بين الصينية/الإنجليزية والرموز غير الطبيعية. يدمج أوضاع التفكير وغير التفكير مع قوالب محادثة للتبديل المرن. كما يعزز أداء وكلاء الشيفرة والبحث لاستخدام أدوات أكثر موثوقية ومهام متعددة الخطوات.",
"Pro/deepseek-ai/DeepSeek-V3.2.description": "DeepSeek-V3.2 هو نموذج يجمع بين الكفاءة الحسابية العالية وأداء التفكير والوكيل الممتاز. يعتمد نهجه على ثلاثة اختراقات تكنولوجية رئيسية: DeepSeek Sparse Attention (DSA)، وهي آلية انتباه فعالة تقلل بشكل كبير من التعقيد الحسابي مع الحفاظ على أداء النموذج، ومُحسنة خصيصًا للسيناريوهات ذات السياق الطويل؛ إطار عمل للتعلم المعزز القابل للتوسع يمكن من خلاله أن ينافس أداء النموذج GPT-5، مع نسخته عالية الحوسبة التي تضاهي Gemini-3.0-Pro في قدرات التفكير؛ وخط أنابيب واسع النطاق لتوليف مهام الوكيل يهدف إلى دمج قدرات التفكير في سيناريوهات استخدام الأدوات، مما يحسن اتباع التعليمات والتعميم في البيئات التفاعلية المعقدة. حقق النموذج أداءً متميزًا في الأولمبياد الدولي للرياضيات (IMO) وأولمبياد المعلوماتية الدولي (IOI) لعام 2025.",
@@ -120,10 +127,10 @@
"Pro/moonshotai/Kimi-K2-Instruct-0905.description": "Kimi K2-Instruct-0905 هو أحدث وأقوى إصدار من Kimi K2. إنه نموذج MoE من الدرجة الأولى يحتوي على إجمالي 1 تريليون و32 مليار معلمة نشطة. من أبرز ميزاته الذكاء البرمجي القوي مع تحسينات كبيرة في المعايير ومهام الوكلاء الواقعية، بالإضافة إلى تحسينات في جمالية واجهة الشيفرة وسهولة الاستخدام.",
"Pro/moonshotai/Kimi-K2-Thinking.description": "Kimi K2 Thinking Turbo هو إصدار Turbo محسّن لسرعة الاستدلال والإنتاجية مع الحفاظ على قدرات التفكير متعدد الخطوات واستخدام الأدوات في K2 Thinking. إنه نموذج MoE يحتوي على حوالي 1 تريليون معلمة إجمالية، ويدعم سياقًا أصليًا بطول 256 ألف رمز، واستدعاء أدوات واسع النطاق ومستقر لسيناريوهات الإنتاج التي تتطلب زمن استجابة وتزامنًا صارمين.",
"Pro/moonshotai/Kimi-K2.5.description": "Kimi K2.5 هو نموذج وكيل متعدد الوسائط مفتوح المصدر، مبني على Kimi-K2-Base، ومدرب على حوالي 1.5 تريليون رمز من النصوص والرؤية. يستخدم بنية MoE بعدد إجمالي 1 تريليون مع 32 مليار معلمات نشطة، ويدعم نافذة سياق تصل إلى 256 ألف، مما يدمج الفهم البصري واللغوي بسلاسة.",
"Pro/zai-org/glm-4.7.description": "GLM-4.7 هو النموذج الرائد من الجيل الجديد لشركة Zhipu، يحتوي على 355 مليار معلمة إجمالية و32 مليار معلمة نشطة، وقد تم تطويره بالكامل في مجالات الحوار العام، والاستدلال، وقدرات الوكلاء. يعزز GLM-4.7 التفكير المتداخل ويقدم مفاهيم التفكير المحفوظ والتفكير على مستوى الدور.",
"Pro/zai-org/glm-4.7.description": "GLM-4.7 هو النموذج الرائد الجديد من Zhipu مع 355 مليار معلمة إجمالية و32 مليار معلمة نشطة، تم ترقيته بالكامل في الحوار العام، المنطق، وقدرات الوكلاء. يعزز GLM-4.7 التفكير المتداخل ويقدم التفكير المحفوظ والتفكير على مستوى الدور.",
"Pro/zai-org/glm-5.description": "GLM-5 هو نموذج اللغة الكبير من الجيل التالي من Zhipu، يركز على هندسة الأنظمة المعقدة ومهام الوكيل طويلة المدة. تم توسيع معلمات النموذج إلى 744 مليار (40 مليار نشطة) وتدمج DeepSeek Sparse Attention.",
"QwQ-32B-Preview.description": "Qwen QwQ هو نموذج بحث تجريبي يركز على تحسين الاستدلال.",
"Qwen/QVQ-72B-Preview.description": "QVQ-72B-Preview هو نموذج بحث من Qwen يركز على الاستدلال البصري، يتميز بفهم المشاهد المعقدة وحل مسائل الرياضيات البصرية.",
"Qwen/QVQ-72B-Preview.description": "QVQ-72B-Preview هو نموذج بحثي من Qwen يركز على الاستدلال البصري، مع قوة في فهم المشاهد المعقدة ومسائل الرياضيات البصرية.",
"Qwen/QwQ-32B-Preview.description": "Qwen QwQ هو نموذج بحث تجريبي يركز على تحسين استدلال الذكاء الاصطناعي.",
"Qwen/QwQ-32B.description": "QwQ هو نموذج استدلال ضمن عائلة Qwen. مقارنة بالنماذج التقليدية الموجهة للتعليمات، يضيف QwQ قدرات تفكير واستدلال تعزز الأداء بشكل كبير في المهام الصعبة. QwQ-32B هو نموذج استدلال متوسط الحجم ينافس نماذج استدلال رائدة مثل DeepSeek-R1 وo1-mini. يستخدم RoPE، SwiGLU، RMSNorm، وانحياز QKV في الانتباه، مع 64 طبقة و40 رأس انتباه (8 KV في GQA).",
"Qwen/Qwen-Image-Edit-2509.description": "Qwen-Image-Edit-2509 هو أحدث إصدار لتحرير الصور من فريق Qwen. مبني على نموذج Qwen-Image بحجم 20 مليار معلمة، ويمتد من قدرات عرض النصوص القوية إلى تحرير الصور بدقة. يستخدم بنية تحكم مزدوجة، حيث تُرسل المدخلات إلى Qwen2.5-VL للتحكم الدلالي وإلى مشفر VAE للتحكم في المظهر، مما يتيح تحريرًا على مستوى الدلالة والمظهر. يدعم التعديلات المحلية (إضافة/إزالة/تعديل) والتعديلات الدلالية المتقدمة مثل إنشاء الملكية الفكرية ونقل الأسلوب مع الحفاظ على المعنى. يحقق نتائج رائدة في العديد من المعايير.",
@@ -207,11 +214,11 @@
"Skylark2-pro-turbo-8k.description": "الجيل الثاني من نموذج Skylark. يوفر Skylark2-pro-turbo-8k استدلالًا أسرع بتكلفة أقل مع نافذة سياق تصل إلى 8 آلاف رمز.",
"THUDM/GLM-4-32B-0414.description": "GLM-4-32B-0414 هو نموذج GLM من الجيل التالي يحتوي على 32 مليار معامل، ويقارن في الأداء مع نماذج OpenAI GPT وسلسلة DeepSeek V3/R1.",
"THUDM/GLM-4-9B-0414.description": "GLM-4-9B-0414 هو نموذج GLM يحتوي على 9 مليارات معامل، ويعتمد على تقنيات GLM-4-32B مع إمكانية نشر أخف. يتميز في توليد الشيفرات، وتصميم الويب، وتوليد SVG، والكتابة المعتمدة على البحث.",
"THUDM/GLM-4.1V-9B-Thinking.description": "GLM-4.1V-9B-Thinking هو نموذج رؤية-لغة مفتوح المصدر من Zhipu AI ومختبر KEG بجامعة تسينغهوا، مصمم للإدراك المعقد متعدد الوسائط. يعتمد على GLM-4-9B-0414 ويضيف سلسلة التفكير والتعلم المعزز لتحسين الاستدلال عبر الوسائط والاستقرار بشكل كبير.",
"THUDM/GLM-4.1V-9B-Thinking.description": "GLM-4.1V-9B-Thinking هو نموذج مفتوح المصدر من Zhipu AI ومختبر Tsinghua KEG، مصمم للإدراك متعدد الوسائط المعقد. يعتمد على GLM-4-9B-0414، ويضيف التفكير المتسلسل والتعلم المعزز لتحسين الاستدلال عبر الوسائط والثبات بشكل كبير.",
"THUDM/GLM-Z1-32B-0414.description": "GLM-Z1-32B-0414 هو نموذج استدلال عميق مبني على GLM-4-32B-0414 باستخدام بيانات بدء باردة وتوسيع التعلم المعزز، وتم تدريبه بشكل إضافي على الرياضيات والبرمجة والمنطق. يُظهر تحسنًا كبيرًا في القدرة على حل المسائل الرياضية والمهام المعقدة مقارنة بالنموذج الأساسي.",
"THUDM/GLM-Z1-9B-0414.description": "GLM-Z1-9B-0414 هو نموذج GLM صغير يحتوي على 9 مليارات معامل، يحتفظ بقوة المصدر المفتوح ويقدم أداءً مميزًا. يتميز في الاستدلال الرياضي والمهام العامة، ويتفوق على النماذج المفتوحة من نفس الفئة الحجمية.",
"THUDM/glm-4-9b-chat.description": "GLM-4-9B-Chat هو النموذج مفتوح المصدر من Zhipu AI ضمن سلسلة GLM-4. يتميز بقوة في الفهم الدلالي، والرياضيات، والاستدلال، والبرمجة، والمعرفة. بالإضافة إلى الدردشة متعددة الأدوار، يدعم تصفح الويب، وتنفيذ الشيفرات، واستدعاء الأدوات المخصصة، والاستدلال على النصوص الطويلة. يدعم 26 لغة (بما في ذلك الصينية، والإنجليزية، واليابانية، والكورية، والألمانية). يحقق أداءً جيدًا في AlignBench-v2 وMT-Bench وMMLU وC-Eval، ويدعم نافذة سياق تصل إلى 128 ألف رمز للاستخدام الأكاديمي والتجاري.",
"Tongyi-Zhiwen/QwenLong-L1-32B.description": "QwenLong-L1-32B هو أول نموذج استدلال طويل السياق (LRM) تم تدريبه باستخدام التعلم المعزز، ومُحسَّن للاستدلال على النصوص الطويلة. تتيح استراتيجية التوسيع التدريجي للسياق انتقالًا مستقرًا من السياقات القصيرة إلى الطويلة. يتفوق على OpenAI-o3-mini وQwen3-235B-A22B في سبعة اختبارات استدلال على مستندات طويلة، ويضاهي Claude-3.7-Sonnet-Thinking. يتميز بقوة خاصة في الرياضيات والمنطق والاستدلال متعدد الخطوات.",
"Tongyi-Zhiwen/QwenLong-L1-32B.description": "QwenLong-L1-32B هو أول نموذج استدلال طويل السياق (LRM) تم تدريبه باستخدام التعلم المعزز، مُحسن للاستدلال النصي الطويل. يتيح التوسع التدريجي للسياق عبر التعلم المعزز انتقالًا مستقرًا من السياق القصير إلى الطويل. يتفوق على OpenAI-o3-mini وQwen3-235B-A22B في سبعة معايير استدلال وثائق طويلة السياق، منافسًا Claude-3.7-Sonnet-Thinking. يتميز بقوة خاصة في الرياضيات، المنطق، والاستدلال متعدد الخطوات.",
"Yi-34B-Chat.description": "Yi-1.5-34B يحتفظ بقدرات اللغة العامة القوية للسلسلة، ويستخدم تدريبًا تدريجيًا على 500 مليار رمز عالي الجودة لتحسين كبير في المنطق الرياضي والبرمجة.",
"abab5.5-chat.description": "مصمم لسيناريوهات الإنتاجية، مع قدرة على التعامل مع المهام المعقدة وتوليد نصوص فعالة للاستخدام المهني.",
"abab5.5s-chat.description": "مصمم للدردشة بشخصيات صينية، ويقدم حوارات صينية عالية الجودة لمجموعة متنوعة من التطبيقات.",
@@ -303,16 +310,16 @@
"claude-3.5-sonnet.description": "يتميز Claude 3.5 Sonnet بقدرات عالية في البرمجة والكتابة والتفكير المعقد.",
"claude-3.7-sonnet-thought.description": "Claude 3.7 Sonnet مزود بقدرات تفكير موسعة للمهام التي تتطلب استدلالًا معقدًا.",
"claude-3.7-sonnet.description": "Claude 3.7 Sonnet هو إصدار مطور يتمتع بسياق موسع وقدرات محسّنة.",
"claude-haiku-4-5-20251001.description": "Claude Haiku 4.5 هو أسرع وأذكى نموذج Haiku من Anthropic، يتميز بسرعة البرق والتفكير الممتد.",
"claude-haiku-4-5-20251001.description": "Claude Haiku 4.5 هو النموذج الأسرع والأكثر ذكاءً من Anthropic، مع سرعة فائقة وتفكير ممتد.",
"claude-haiku-4.5.description": "Claude Haiku 4.5 نموذج سريع وفعّال لمجموعة متنوعة من المهام.",
"claude-opus-4-1-20250805-thinking.description": "Claude Opus 4.1 Thinking هو إصدار متقدم يمكنه عرض عملية تفكيره.",
"claude-opus-4-1-20250805.description": "Claude Opus 4.1 هو أحدث وأقوى نموذج من Anthropic للمهام المعقدة للغاية، يتميز بالأداء والذكاء والطلاقة والفهم.",
"claude-opus-4-20250514.description": "Claude Opus 4 هو أقوى نموذج من Anthropic للمهام المعقدة للغاية، يتميز بالأداء والذكاء والطلاقة والفهم.",
"claude-opus-4-1-20250805.description": "Claude Opus 4.1 هو أحدث وأقوى نموذج من Anthropic للمهام المعقدة للغاية، يتميز بالأداء، الذكاء، الطلاقة، والفهم.",
"claude-opus-4-20250514.description": "Claude Opus 4 هو النموذج الأكثر قوة من Anthropic للمهام المعقدة للغاية، يتميز بالأداء، الذكاء، الطلاقة، والفهم.",
"claude-opus-4-5-20251101.description": "Claude Opus 4.5 هو النموذج الرائد من Anthropic، يجمع بين الذكاء الاستثنائي والأداء القابل للتوسع، مثالي للمهام المعقدة التي تتطلب استجابات عالية الجودة وتفكير متقدم.",
"claude-opus-4-6.description": "Claude Opus 4.6 هو أذكى نموذج من Anthropic لبناء الوكلاء والبرمجة.",
"claude-opus-4-6.description": "Claude Opus 4.6 هو النموذج الأكثر ذكاءً من Anthropic لبناء الوكلاء والبرمجة.",
"claude-sonnet-4-20250514-thinking.description": "Claude Sonnet 4 Thinking يمكنه تقديم استجابات شبه فورية أو تفكير متسلسل مرئي.",
"claude-sonnet-4-20250514.description": "Claude Sonnet 4 هو أذكى نموذج من Anthropic حتى الآن، يقدم استجابات شبه فورية أو تفكير ممتد خطوة بخطوة مع تحكم دقيق لمستخدمي API.",
"claude-sonnet-4-5-20250929.description": "Claude Sonnet 4.5 هو أذكى نموذج من Anthropic حتى الآن.",
"claude-sonnet-4-20250514.description": "Claude Sonnet 4 هو النموذج الأكثر ذكاءً من Anthropic حتى الآن، يقدم استجابات شبه فورية أو تفكيرًا ممتدًا خطوة بخطوة مع تحكم دقيق لمستخدمي API.",
"claude-sonnet-4-5-20250929.description": "Claude Sonnet 4.5 هو النموذج الأكثر ذكاءً من Anthropic حتى الآن.",
"claude-sonnet-4-6.description": "Claude Sonnet 4.6 هو أفضل مزيج من السرعة والذكاء من Anthropic.",
"claude-sonnet-4.description": "Claude Sonnet 4 هو الجيل الأحدث مع أداء محسّن في جميع المهام.",
"codegeex-4.description": "CodeGeeX-4 هو مساعد برمجة ذكي يدعم الأسئلة والأجوبة متعددة اللغات وإكمال الشيفرة لزيادة إنتاجية المطورين.",
@@ -370,7 +377,7 @@
"deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B.description": "تستخدم نماذج DeepSeek-R1 المستخلصة التعلم المعزز وبيانات البداية الباردة لتحسين التفكير وتحديد معايير جديدة للنماذج المفتوحة متعددة المهام.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-14B.description": "تستخدم نماذج DeepSeek-R1 المستخلصة التعلم المعزز وبيانات البداية الباردة لتحسين التفكير وتحديد معايير جديدة للنماذج المفتوحة متعددة المهام.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-32B.description": "تم استخلاص DeepSeek-R1-Distill-Qwen-32B من Qwen2.5-32B وتم تحسينه باستخدام 800 ألف عينة مختارة من DeepSeek-R1. يتميز في الرياضيات، والبرمجة، والتفكير، ويحقق نتائج قوية في AIME 2024، وMATH-500 (بدقة 94.3٪)، وGPQA Diamond.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "تم استخلاص DeepSeek-R1-Distill-Qwen-7B من Qwen2.5-Math-7B وتم تحسينه باستخدام 800 ألف عينة مختارة من DeepSeek-R1. يحقق أداءً قويًا بنسبة 92.8٪ في MATH-500، و55.5٪ في AIME 2024، وتصنيف 1189 في CodeForces لنموذج بحجم 7B.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "DeepSeek-R1-Distill-Qwen-7B مستخلص من Qwen2.5-Math-7B ومُحسن على 800 ألف عينة مختارة من DeepSeek-R1. يقدم أداءً قويًا، بنسبة 92.8% على MATH-500، و55.5% على AIME 2024، وتصنيف 1189 على CodeForces لنموذج 7B.",
"deepseek-ai/DeepSeek-R1.description": "يعزز DeepSeek-R1 قدرات التفكير باستخدام التعلم المعزز وبيانات البداية الباردة، ويحدد معايير جديدة للنماذج المفتوحة متعددة المهام متفوقًا على OpenAI-o1-mini.",
"deepseek-ai/DeepSeek-V2.5.description": "يعمل DeepSeek-V2.5 على ترقية DeepSeek-V2-Chat وDeepSeek-Coder-V2-Instruct، ويمزج بين القدرات العامة والبرمجية. يحسن الكتابة واتباع التعليمات لمواءمة التفضيلات بشكل أفضل، ويظهر تحسنًا ملحوظًا في AlpacaEval 2.0 وArenaHard وAlignBench وMT-Bench.",
"deepseek-ai/DeepSeek-V3.1-Terminus.description": "DeepSeek-V3.1-Terminus هو إصدار محدث من V3.1 كنموذج وكيل هجين. يعالج المشكلات التي أبلغ عنها المستخدمون ويحسن الاستقرار واتساق اللغة ويقلل من الخلط بين الصينية/الإنجليزية والرموز غير الطبيعية. يدمج أوضاع التفكير وغير التفكير مع قوالب المحادثة للتبديل المرن. كما يعزز أداء وكلاء الكود والبحث لاستخدام الأدوات بشكل أكثر موثوقية وتنفيذ المهام متعددة الخطوات.",
@@ -383,7 +390,7 @@
"deepseek-ai/deepseek-v3.1.description": "DeepSeek V3.1 هو نموذج تفكير من الجيل التالي يتمتع بقدرات أقوى في التفكير المعقد وسلسلة التفكير لمهام التحليل العميق.",
"deepseek-ai/deepseek-v3.2.description": "DeepSeek V3.2 هو نموذج استدلال من الجيل التالي يتميز بقدرات استدلال معقدة وسلسلة التفكير.",
"deepseek-ai/deepseek-vl2.description": "DeepSeek-VL2 هو نموذج رؤية-لغة MoE يعتمد على DeepSeekMoE-27B مع تنشيط متفرق، ويحقق أداءً قويًا باستخدام 4.5 مليار معلمة نشطة فقط. يتميز في الأسئلة البصرية، وOCR، وفهم المستندات/الجداول/المخططات، والتأريض البصري.",
"deepseek-chat.description": "DeepSeek V3.2 يوازن بين التفكير وطول المخرجات لمهام الأسئلة اليومية ووكلاء المهام. تصل المعايير العامة إلى مستويات GPT-5، وهو الأول في دمج التفكير في استخدام الأدوات، مما يؤدي إلى تقييمات وكلاء مفتوحة المصدر.",
"deepseek-chat.description": "DeepSeek V3.2 يوازن بين التفكير وطول المخرجات لمهام الأسئلة اليومية والوكلاء. تصل المعايير العامة إلى مستويات GPT-5، وهو الأول الذي يدمج التفكير في استخدام الأدوات، مما يؤدي إلى تقييمات الوكلاء مفتوحة المصدر.",
"deepseek-coder-33B-instruct.description": "DeepSeek Coder 33B هو نموذج لغة برمجية تم تدريبه على 2 تريليون رمز (87٪ كود، 13٪ نص صيني/إنجليزي). يقدم نافذة سياق 16K ومهام الإكمال في المنتصف، ويوفر إكمال كود على مستوى المشاريع وملء مقاطع الكود.",
"deepseek-coder-v2.description": "DeepSeek Coder V2 هو نموذج كود MoE مفتوح المصدر يتميز بأداء قوي في مهام البرمجة، ويضاهي GPT-4 Turbo.",
"deepseek-coder-v2:236b.description": "DeepSeek Coder V2 هو نموذج كود MoE مفتوح المصدر يتميز بأداء قوي في مهام البرمجة، ويضاهي GPT-4 Turbo.",
@@ -406,7 +413,7 @@
"deepseek-r1-fast-online.description": "الإصدار الكامل السريع من DeepSeek R1 مع بحث ويب في الوقت الحقيقي، يجمع بين قدرات بحجم 671B واستجابة أسرع.",
"deepseek-r1-online.description": "الإصدار الكامل من DeepSeek R1 مع 671 مليار معلمة وبحث ويب في الوقت الحقيقي، يوفر فهمًا وتوليدًا أقوى.",
"deepseek-r1.description": "يستخدم DeepSeek-R1 بيانات البداية الباردة قبل التعلم المعزز ويؤدي أداءً مماثلًا لـ OpenAI-o1 في الرياضيات، والبرمجة، والتفكير.",
"deepseek-reasoner.description": "DeepSeek V3.2 Thinking هو نموذج تفكير عميق يولد سلسلة من الأفكار قبل المخرجات لتحقيق دقة أعلى، مع نتائج تنافسية عالية وتفكير مشابه لـ Gemini-3.0-Pro.",
"deepseek-reasoner.description": "DeepSeek V3.2 Thinking هو نموذج استدلال عميق يولد سلسلة من الأفكار قبل المخرجات لتحقيق دقة أعلى، مع نتائج تنافسية رائدة واستدلال قابل للمقارنة مع Gemini-3.0-Pro.",
"deepseek-v2.description": "DeepSeek V2 هو نموذج MoE فعال لمعالجة منخفضة التكلفة.",
"deepseek-v2:236b.description": "DeepSeek V2 236B هو نموذج DeepSeek الموجه للبرمجة مع قدرات قوية في توليد الكود.",
"deepseek-v3-0324.description": "DeepSeek-V3-0324 هو نموذج MoE يحتوي على 671 مليار معلمة يتميز بقوة في البرمجة، والقدرات التقنية، وفهم السياق، والتعامل مع النصوص الطويلة.",
@@ -417,7 +424,7 @@
"deepseek-v3.2-exp.description": "deepseek-v3.2-exp يقدم انتباهاً متفرقاً لتحسين كفاءة التدريب والاستدلال على النصوص الطويلة، بسعر أقل من deepseek-v3.1.",
"deepseek-v3.2-speciale.description": "في المهام شديدة التعقيد، يتفوق نموذج Speciale بشكل كبير على النسخة القياسية، ولكنه يستهلك عددًا كبيرًا من الرموز ويتكبد تكاليف أعلى. حاليًا، يتم استخدام DeepSeek-V3.2-Speciale للأبحاث فقط، ولا يدعم استدعاء الأدوات، ولم يتم تحسينه بشكل خاص للمحادثات اليومية أو مهام الكتابة.",
"deepseek-v3.2-think.description": "DeepSeek V3.2 Think هو نموذج تفكير عميق كامل يتميز باستدلال طويل السلسلة أقوى.",
"deepseek-v3.2.description": "DeepSeek-V3.2 هو أول نموذج استدلال هجين من DeepSeek يدمج التفكير في استخدام الأدوات. يستخدم بنية فعالة لتقليل الحسابات، وتعلم تقوية واسع النطاق لتعزيز القدرات، وبيانات مهام تركيبية ضخمة لتعزيز التعميم. يجمع بين هذه العناصر الثلاثة لتحقيق أداء مماثل لـ GPT-5-High، مع تقليل كبير في طول المخرجات، مما يقلل من عبء الحوسبة وأوقات انتظار المستخدمين.",
"deepseek-v3.2.description": "DeepSeek-V3.2 هو أحدث نموذج برمجة من DeepSeek مع قدرات استدلال قوية.",
"deepseek-v3.description": "DeepSeek-V3 هو نموذج MoE قوي بإجمالي 671 مليار معلمة و37 مليار معلمة نشطة لكل رمز.",
"deepseek-vl2-small.description": "DeepSeek VL2 Small هو إصدار متعدد الوسائط خفيف الوزن للاستخدام في البيئات ذات الموارد المحدودة أو التزامن العالي.",
"deepseek-vl2.description": "DeepSeek VL2 هو نموذج متعدد الوسائط لفهم النصوص والصور والإجابة البصرية الدقيقة.",
@@ -506,8 +513,8 @@
"ernie-x1-turbo-32k.description": "ERNIE X1 Turbo 32K هو نموذج تفكير سريع بسياق 32K للاستدلال المعقد والدردشة متعددة الأدوار.",
"ernie-x1.1-preview.description": "معاينة ERNIE X1.1 هو نموذج تفكير مخصص للتقييم والاختبار.",
"ernie-x1.1.description": "ERNIE X1.1 هو نموذج تفكير تجريبي للتقييم والاختبار.",
"fal-ai/bytedance/seedream/v4.5.description": "Seedream 4.5، الذي تم تطويره بواسطة فريق ByteDance Seed، يدعم تحرير الصور المتعددة والتكوين. يتميز بتناسق الموضوع المحسن، اتباع التعليمات بدقة، فهم المنطق المكاني، التعبير الجمالي، تصميم الملصقات والشعارات مع تقديم نصوص وصور عالية الدقة.",
"fal-ai/bytedance/seedream/v4.description": "Seedream 4.0، الذي تم تطويره بواسطة ByteDance Seed، يدعم إدخال النصوص والصور لإنشاء صور عالية الجودة وقابلة للتحكم بناءً على التعليمات.",
"fal-ai/bytedance/seedream/v4.5.description": "Seedream 4.5، تم تطويره بواسطة فريق ByteDance Seed، يدعم تحرير وتكوين الصور المتعددة. يتميز باتساق الموضوع المعزز، اتباع التعليمات بدقة، فهم المنطق المكاني، التعبير الجمالي، تخطيط الملصقات وتصميم الشعارات مع تقديم نصوص وصور عالية الدقة.",
"fal-ai/bytedance/seedream/v4.description": "Seedream 4.0، تم تطويره بواسطة ByteDance Seed، يدعم إدخال النصوص والصور لتوليد صور عالية الجودة وقابلة للتحكم من المطالبات.",
"fal-ai/flux-kontext/dev.description": "نموذج FLUX.1 يركز على تحرير الصور، ويدعم إدخال النصوص والصور.",
"fal-ai/flux-pro/kontext.description": "FLUX.1 Kontext [pro] يقبل النصوص وصور مرجعية كمدخلات، مما يتيح تعديلات محلية مستهدفة وتحولات معقدة في المشهد العام.",
"fal-ai/flux/krea.description": "Flux Krea [dev] هو نموذج لتوليد الصور يتميز بميول جمالية نحو صور أكثر واقعية وطبيعية.",
@@ -515,8 +522,8 @@
"fal-ai/hunyuan-image/v3.description": "نموذج قوي لتوليد الصور متعدد الوسائط أصلي.",
"fal-ai/imagen4/preview.description": "نموذج عالي الجودة لتوليد الصور من Google.",
"fal-ai/nano-banana.description": "Nano Banana هو أحدث وأسرع وأكثر نماذج Google كفاءةً لتوليد وتحرير الصور من خلال المحادثة.",
"fal-ai/qwen-image-edit.description": "نموذج تحرير الصور الاحترافي من فريق Qwen، يدعم التعديلات الدلالية والمظهرية، تحرير النصوص الدقيقة باللغتين الصينية والإنجليزية، نقل الأسلوب، الدوران، والمزيد.",
"fal-ai/qwen-image.description": "نموذج قوي لإنشاء الصور من فريق Qwen يتميز بتقديم نصوص صينية قوية وأنماط بصرية متنوعة.",
"fal-ai/qwen-image-edit.description": "نموذج تحرير الصور الاحترافي من فريق Qwen، يدعم التعديلات الدلالية والمظهرية، تحرير النصوص الدقيقة باللغتين الصينية والإنجليزية، نقل الأنماط، التدوير، والمزيد.",
"fal-ai/qwen-image.description": "نموذج توليد الصور القوي من فريق Qwen مع تقديم نصوص صينية قوية وأنماط بصرية متنوعة.",
"flux-1-schnell.description": "نموذج تحويل النص إلى صورة يحتوي على 12 مليار معلمة من Black Forest Labs يستخدم تقنيات تقطير الانتشار العدائي الكامن لتوليد صور عالية الجودة في 1-4 خطوات. ينافس البدائل المغلقة ومتاح بموجب ترخيص Apache-2.0 للاستخدام الشخصي والبحثي والتجاري.",
"flux-dev.description": "FLUX.1 [dev] هو نموذج مفتوح الأوزان ومقطر للاستخدام غير التجاري. يحافظ على جودة صور قريبة من المستوى الاحترافي واتباع التعليمات مع كفاءة تشغيل أعلى مقارنة بالنماذج القياسية من نفس الحجم.",
"flux-kontext-max.description": "توليد وتحرير صور سياقية متقدمة، تجمع بين النصوص والصور لتحقيق نتائج دقيقة ومتسقة.",
@@ -560,10 +567,10 @@
"gemini-2.5-pro.description": "Gemini 2.5 Pro هو النموذج الرائد من Google في مجال الاستدلال، يدعم السياق الطويل للمهام المعقدة.",
"gemini-3-flash-preview.description": "Gemini 3 Flash هو أذكى نموذج تم تصميمه للسرعة، يجمع بين الذكاء المتقدم وأساس بحث ممتاز.",
"gemini-3-pro-image-preview.description": "Gemini 3 Pro Image (Nano Banana Pro) هو نموذج توليد الصور من Google ويدعم المحادثة متعددة الوسائط.",
"gemini-3-pro-image-preview:image.description": "Gemini 3 Pro Image (Nano Banana Pro) هو نموذج إنشاء الصور من Google ويدعم أيضًا الدردشة متعددة الوسائط.",
"gemini-3-pro-image-preview:image.description": "Gemini 3 Pro Image (Nano Banana Pro) هو نموذج توليد الصور من Google ويدعم أيضًا الدردشة متعددة الوسائط.",
"gemini-3-pro-preview.description": "Gemini 3 Pro هو أقوى نموذج من Google للوكيل الذكي والبرمجة الإبداعية، يقدم تفاعلاً أعمق وصورًا أغنى مع استدلال متقدم.",
"gemini-3.1-flash-image-preview.description": "Gemini 3.1 Flash Image (Nano Banana 2) يقدم جودة صور احترافية بسرعة فائقة مع دعم الدردشة متعددة الوسائط.",
"gemini-3.1-flash-image-preview:image.description": "Gemini 3.1 Flash Image (Nano Banana 2) يقدم جودة صور بمستوى احترافي بسرعة Flash مع دعم الدردشة متعددة الوسائط.",
"gemini-3.1-flash-image-preview:image.description": "Gemini 3.1 Flash Image (Nano Banana 2) يقدم جودة صور بمستوى Pro بسرعة Flash مع دعم الدردشة متعددة الوسائط.",
"gemini-3.1-flash-lite-preview.description": "Gemini 3.1 Flash-Lite Preview هو النموذج الأكثر كفاءة من حيث التكلفة من Google، مُحسّن للمهام الوكيلة ذات الحجم الكبير، الترجمة، ومعالجة البيانات.",
"gemini-3.1-pro-preview.description": "Gemini 3.1 Pro Preview يحسن من Gemini 3 Pro مع قدرات استدلال محسّنة ويضيف دعم مستوى التفكير المتوسط.",
"gemini-flash-latest.description": "أحدث إصدار من Gemini Flash",
@@ -798,7 +805,7 @@
"kimi-k2-thinking-turbo.description": "إصدار K2 عالي السرعة للتفكير الطويل مع نافذة سياق 256k، استدلال عميق قوي، وإخراج 60–100 رمز/ثانية.",
"kimi-k2-thinking.description": "kimi-k2-thinking هو نموذج تفكير من Moonshot AI يتمتع بقدرات عامة في الوكالة والاستدلال. يتفوق في الاستدلال العميق ويمكنه حل المشكلات الصعبة باستخدام أدوات متعددة الخطوات.",
"kimi-k2-turbo-preview.description": "kimi-k2 هو نموذج MoE أساسي يتمتع بقدرات قوية في البرمجة والوكالة (1 تريليون معلمة إجمالية، 32 مليار نشطة)، ويتفوق على النماذج المفتوحة السائدة في اختبارات الاستدلال، البرمجة، الرياضيات، والوكالة.",
"kimi-k2.5.description": "Kimi K2.5 هو أقوى نموذج من سلسلة Kimi، يقدم أداءً رائدًا مفتوح المصدر في مهام الوكلاء، البرمجة، وفهم الرؤية. يدعم الإدخال متعدد الوسائط وأنماط التفكير وغير التفكير.",
"kimi-k2.5.description": "Kimi K2.5 هو النموذج الأكثر تنوعًا من Kimi حتى الآن، يتميز ببنية متعددة الوسائط تدعم المدخلات البصرية والنصية، أوضاع \"التفكير\" و\"غير التفكير\"، ومهام المحادثة والوكلاء.",
"kimi-k2.description": "Kimi-K2 هو نموذج MoE أساسي من Moonshot AI يتمتع بقدرات قوية في البرمجة والوكالة، بإجمالي 1 تريليون معلمة و32 مليار نشطة. يتفوق على النماذج المفتوحة السائدة في اختبارات الاستدلال العام، البرمجة، الرياضيات، ومهام الوكالة.",
"kimi-k2:1t.description": "Kimi K2 هو نموذج LLM كبير من نوع MoE من Moonshot AI بإجمالي 1 تريليون معلمة و32 مليار نشطة لكل تمرير أمامي. مُحسّن لقدرات الوكالة بما في ذلك استخدام الأدوات المتقدمة، الاستدلال، وتوليد الشيفرة.",
"kuaishou/kat-coder-pro-v1.description": "KAT-Coder-Pro-V1 (مجاني لفترة محدودة) يركز على فهم الشيفرة والأتمتة لوكلاء البرمجة الفعالة.",
@@ -960,7 +967,7 @@
"moonshot-v1-32k.description": "Moonshot V1 32K يدعم 32,768 رمزًا لسياق متوسط الطول، وهو مثالي للوثائق الطويلة والحوارات المعقدة في إنشاء المحتوى، والتقارير، وأنظمة الدردشة.",
"moonshot-v1-8k-vision-preview.description": "نماذج Kimi للرؤية (بما في ذلك moonshot-v1-8k-vision-preview/moonshot-v1-32k-vision-preview/moonshot-v1-128k-vision-preview) قادرة على فهم محتوى الصور مثل النصوص، الألوان، وأشكال الكائنات.",
"moonshot-v1-8k.description": "Moonshot V1 8K مُحسّن لتوليد النصوص القصيرة بكفاءة عالية، حيث يتعامل مع 8,192 رمزًا للمحادثات القصيرة، والملاحظات، والمحتوى السريع.",
"moonshotai/Kimi-Dev-72B.description": "Kimi-Dev-72B هو نموذج مفتوح المصدر للبرمجة تم تحسينه باستخدام التعلم المعزز على نطاق واسع لإنتاج تصحيحات قوية وجاهزة للإنتاج. يحقق نسبة 60.4٪ على SWE-bench Verified، مسجلاً رقمًا قياسيًا جديدًا للنماذج المفتوحة في مهام هندسة البرمجيات الآلية مثل إصلاح الأخطاء ومراجعة الشيفرة.",
"moonshotai/Kimi-Dev-72B.description": "Kimi-Dev-72B هو نموذج برمجة مفتوح المصدر مُحسن باستخدام التعلم المعزز واسع النطاق لإنتاج تصحيحات قوية وجاهزة للإنتاج. يسجل 60.4% على SWE-bench Verified، محققًا رقمًا قياسيًا جديدًا للنماذج المفتوحة في مهام هندسة البرمجيات الآلية مثل إصلاح الأخطاء ومراجعة الكود.",
"moonshotai/Kimi-K2-Instruct-0905.description": "Kimi K2-Instruct-0905 هو أحدث وأقوى إصدار من Kimi K2. إنه نموذج MoE من الدرجة الأولى يحتوي على تريليون معلمة إجمالية و32 مليار معلمة نشطة. من أبرز ميزاته الذكاء البرمجي القوي، وتحسينات كبيرة في اختبارات الأداء والمهام الواقعية، بالإضافة إلى تحسينات في جمالية واجهات الاستخدام وسهولة البرمجة الأمامية.",
"moonshotai/Kimi-K2-Thinking.description": "Kimi K2 Thinking هو أحدث وأقوى نموذج تفكير مفتوح المصدر. يوسع بشكل كبير عمق التفكير متعدد الخطوات ويحافظ على استخدام الأدوات المستقر عبر 200-300 استدعاء متتالي، محققًا أرقامًا قياسية جديدة في Humanity's Last Exam (HLE)، BrowseComp، ومعايير أخرى. يتفوق في البرمجة، الرياضيات، المنطق، وسيناريوهات الوكيل. يعتمد على بنية MoE مع ~1 تريليون معلمة إجمالية، ويدعم نافذة سياق 256K واستدعاء الأدوات.",
"moonshotai/kimi-k2-0711.description": "Kimi K2 0711 هو إصدار موجه من سلسلة Kimi، مناسب للبرمجة عالية الجودة واستخدام الأدوات.",
@@ -1163,6 +1170,7 @@
"qwen3-coder-next.description": "الجيل التالي من Qwen coder محسن لتوليد الأكواد المعقدة متعددة الملفات، وتصحيح الأخطاء، وسير العمل عالي الإنتاجية للوكلاء. مصمم لتكامل الأدوات القوي وتحسين أداء الاستدلال.",
"qwen3-coder-plus.description": "نموذج Qwen للبرمجة. سلسلة Qwen3-Coder الأحدث مبنية على Qwen3 وتوفر قدرات قوية كوكلاء برمجة، واستخدام الأدوات، والتفاعل مع البيئة للبرمجة الذاتية، مع أداء ممتاز في البرمجة وقدرات عامة قوية.",
"qwen3-coder:480b.description": "نموذج عالي الأداء من Alibaba لمعالجة المهام المتعلقة بالوكلاء والبرمجة مع دعم لسياقات طويلة.",
"qwen3-max-2026-01-23.description": "Qwen3 Max: النموذج الأفضل أداءً من Qwen للمهام البرمجية المعقدة متعددة الخطوات مع دعم التفكير.",
"qwen3-max-preview.description": "أفضل نموذج Qwen للأداء في المهام المعقدة متعددة الخطوات. المعاينة تدعم التفكير.",
"qwen3-max.description": "نماذج Qwen3 Max تقدم تحسينات كبيرة مقارنة بسلسلة 2.5 في القدرات العامة، وفهم اللغة الصينية/الإنجليزية، واتباع التعليمات المعقدة، والمهام المفتوحة الذاتية، والقدرات متعددة اللغات، واستخدام الأدوات، مع تقليل الهلوسة. الإصدار الأحدث qwen3-max يعزز البرمجة الوكيلة واستخدام الأدوات مقارنة بـ qwen3-max-preview. هذا الإصدار يحقق أداءً رائداً في المجال ويستهدف احتياجات الوكلاء المعقدة.",
"qwen3-next-80b-a3b-instruct.description": "نموذج Qwen3 من الجيل التالي مفتوح المصدر غير مخصص للتفكير. مقارنة بالإصدار السابق (Qwen3-235B-A22B-Instruct-2507)، يتميز بفهم أفضل للغة الصينية، واستدلال منطقي أقوى، وتحسين في توليد النصوص.",
@@ -1192,8 +1200,8 @@
"qwq.description": "QwQ هو نموذج استدلال من عائلة Qwen. مقارنة بالنماذج المضبوطة على التعليمات، يقدم قدرات تفكير واستدلال تعزز الأداء بشكل كبير، خاصة في المشكلات الصعبة. QwQ-32B هو نموذج متوسط الحجم ينافس أفضل نماذج الاستدلال مثل DeepSeek-R1 و o1-mini.",
"qwq_32b.description": "نموذج استدلال متوسط الحجم من عائلة Qwen. مقارنة بالنماذج المضبوطة على التعليمات، تعزز قدرات التفكير والاستدلال في QwQ الأداء بشكل كبير، خاصة في المشكلات الصعبة.",
"r1-1776.description": "R1-1776 هو إصدار ما بعد التدريب من DeepSeek R1 مصمم لتقديم معلومات واقعية غير خاضعة للرقابة أو التحيز.",
"seedance-1-5-pro-251215.description": "Seedance 1.5 Pro من ByteDance يدعم تحويل النص إلى فيديو، الصورة إلى فيديو (الإطار الأول، الإطار الأول + الأخير)، وإنشاء الصوت متزامنًا مع المرئيات.",
"seedream-5-0-260128.description": "ByteDance-Seedream-5.0-lite من BytePlus يتميز بإنشاء معزز بالاسترجاع عبر الويب للحصول على معلومات في الوقت الحقيقي، تفسير محسّن للتعليمات المعقدة، وتحسين تناسق المراجع لإنشاء بصري احترافي.",
"seedance-1-5-pro-251215.description": "Seedance 1.5 Pro من ByteDance يدعم تحويل النص إلى فيديو، الصورة إلى فيديو (الإطار الأول، الإطار الأول + الأخير)، وتوليد الصوت المتزامن مع المرئيات.",
"seedream-5-0-260128.description": "ByteDance-Seedream-5.0-lite من BytePlus يتميز بتوليد معزز بالمعلومات المسترجعة من الويب للحصول على معلومات في الوقت الفعلي، تفسير المطالبات المعقدة بشكل محسن، وتحسين اتساق المراجع لإنشاء مرئيات احترافية.",
"solar-mini-ja.description": "Solar Mini (Ja) يوسع Solar Mini مع تركيز على اللغة اليابانية مع الحفاظ على الأداء القوي والكفاءة في الإنجليزية والكورية.",
"solar-mini.description": "Solar Mini هو نموذج لغة مدمج يتفوق على GPT-3.5، يتميز بقدرات متعددة اللغات قوية تدعم الإنجليزية والكورية، ويقدم حلاً فعالاً بصمة صغيرة.",
"solar-pro.description": "Solar Pro هو نموذج لغة عالي الذكاء من Upstage، يركز على اتباع التعليمات باستخدام وحدة معالجة رسومات واحدة، مع درجات IFEval تتجاوز 80. حالياً يدعم اللغة الإنجليزية؛ وكان من المقرر إصدار النسخة الكاملة في نوفمبر 2024 مع دعم لغات موسع وسياق أطول.",
@@ -1229,7 +1237,7 @@
"step-3.5-flash.description": "نموذج التفكير اللغوي الرائد من Stepfun. يتميز بقدرات تفكير من الدرجة الأولى وقدرات تنفيذ سريعة وموثوقة. قادر على تحليل وتخطيط المهام المعقدة، واستدعاء الأدوات بسرعة وموثوقية لأداء المهام، والتعامل مع مختلف المهام المعقدة مثل التفكير المنطقي، الرياضيات، هندسة البرمجيات، والبحث المتعمق.",
"step-3.description": "يتمتع هذا النموذج بإدراك بصري قوي واستدلال معقد، ويتعامل بدقة مع فهم المعرفة عبر المجالات، وتحليل الرياضيات والرؤية، ومجموعة واسعة من مهام التحليل البصري اليومية.",
"step-r1-v-mini.description": "نموذج استدلال يتمتع بفهم قوي للصور، يمكنه معالجة الصور والنصوص، ثم توليد نص بعد استدلال عميق. يتفوق في الاستدلال البصري ويقدم أداءً رائدًا في الرياضيات والبرمجة والاستدلال النصي، مع نافذة سياق تصل إلى 100 ألف.",
"stepfun-ai/step3.description": "Step3 هو نموذج استدلال متعدد الوسائط متقدم من StepFun، مبني على بنية MoE بسعة إجمالية 321B و38B نشطة. تصميمه الشامل يقلل من تكلفة فك التشفير مع تقديم استدلال رؤية-لغة من الدرجة الأولى. بفضل تصميم MFA وAFD، يظل فعالًا على المسرعات القوية والضعيفة. تم تدريبه مسبقًا على أكثر من 20 تريليون رمز نصي و4 تريليون رمز صورة-نص بعدة لغات. يحقق أداءً رائدًا في النماذج المفتوحة في اختبارات الرياضيات والبرمجة ومتعددة الوسائط.",
"stepfun-ai/step3.description": "Step3 هو نموذج استدلال متعدد الوسائط متقدم من StepFun، يعتمد على بنية MoE مع 321 مليار معلمة إجمالية و38 مليار معلمة نشطة. تصميمه الشامل يقلل من تكلفة فك التشفير مع تقديم استدلال رؤية-لغة من الدرجة الأولى. مع تصميم MFA وAFD، يظل فعالًا على كل من المسرعات الرائدة والمنخفضة. يستخدم التدريب المسبق أكثر من 20 تريليون رمز نصي و4 تريليون رمز نصي-صوري عبر العديد من اللغات. يحقق أداءً رائدًا للنماذج المفتوحة في الرياضيات، البرمجة، ومعايير متعددة الوسائط.",
"taichu4_vl_2b_nothinking.description": "الإصدار بدون التفكير من نموذج Taichu4.0-VL 2B يتميز باستخدام ذاكرة أقل، تصميم خفيف الوزن، سرعة استجابة سريعة، وقدرات فهم متعددة الوسائط قوية.",
"taichu4_vl_32b.description": "الإصدار التفكير من نموذج Taichu4.0-VL 32B مناسب لمهام الفهم والاستدلال متعددة الوسائط المعقدة، ويظهر أداءً رائعًا في الاستدلال الرياضي متعدد الوسائط، قدرات الوكيل متعدد الوسائط، والفهم العام للصور والبصريات.",
"taichu4_vl_32b_nothinking.description": "الإصدار بدون التفكير من نموذج Taichu4.0-VL 32B مصمم لفهم النصوص والصور المعقدة وسيناريوهات الإجابة على الأسئلة المعرفية البصرية، ويتفوق في وصف الصور، الإجابة على الأسئلة البصرية، فهم الفيديو، ومهام تحديد المواقع البصرية.",
@@ -1316,7 +1324,7 @@
"zai-org/GLM-4.5-Air.description": "GLM-4.5-Air هو نموذج أساسي لتطبيقات الوكلاء يستخدم بنية Mixture-of-Experts. مُحسّن لاستخدام الأدوات، وتصفح الويب، والهندسة البرمجية، وبرمجة الواجهات، ويتكامل مع وكلاء البرمجة مثل Claude Code وRoo Code. يستخدم استدلالًا هجينًا للتعامل مع السيناريوهات المعقدة واليومية.",
"zai-org/GLM-4.5V.description": "GLM-4.5V هو أحدث نموذج رؤية من Zhipu AI، مبني على نموذج النص الرائد GLM-4.5-Air (إجمالي 106 مليار، 12 مليار نشط) باستخدام بنية MoE لأداء قوي بتكلفة أقل. يتبع مسار GLM-4.1V-Thinking ويضيف 3D-RoPE لتحسين الاستدلال المكاني ثلاثي الأبعاد. مُحسّن من خلال التدريب المسبق، والتعلم الخاضع للإشراف، والتعلم المعزز، ويتعامل مع الصور، والفيديو، والمستندات الطويلة، ويتصدر النماذج المفتوحة في 41 معيارًا متعدد الوسائط. يتيح وضع التفكير للمستخدمين التوازن بين السرعة والعمق.",
"zai-org/GLM-4.6.description": "مقارنة بـ GLM-4.5، يوسّع GLM-4.6 السياق من 128 ألف إلى 200 ألف لمهام الوكلاء المعقدة. يحقق نتائج أعلى في اختبارات البرمجة ويُظهر أداءً أقوى في التطبيقات الواقعية مثل Claude Code وCline وRoo Code وKilo Code، بما في ذلك توليد صفحات الواجهة الأمامية بشكل أفضل. تم تحسين الاستدلال ودعم استخدام الأدوات أثناء التفكير، مما يعزز القدرات العامة. يتكامل بشكل أفضل مع أطر الوكلاء، ويحسّن وكلاء الأدوات/البحث، ويتميز بأسلوب كتابة مفضل بشريًا وطبيعية في تقمص الأدوار.",
"zai-org/GLM-4.6V.description": "GLM-4.6V يحقق دقة فهم بصري رائدة بالنسبة لحجم معلماته وهو الأول الذي يدمج قدرات استدعاء الوظائف بشكل طبيعي في بنية نموذج الرؤية، مما يجسر الفجوة بين \"الإدراك البصري\" و\"الإجراءات القابلة للتنفيذ\" ويوفر أساسًا تقنيًا موحدًا للوكلاء متعدد الوسائط في سيناريوهات الأعمال الواقعية. تم تمديد نافذة السياق البصري إلى 128k، مما يدعم معالجة تدفقات الفيديو الطويلة وتحليل الصور عالية الدقة متعددة.",
"zai-org/GLM-4.6V.description": "GLM-4.6V يحقق دقة فهم بصري رائدة بالنسبة لحجم معلماته وهو الأول الذي يدمج قدرات استدعاء الوظائف بشكل طبيعي في بنية نموذج الرؤية، مما يجسر الفجوة بين \"الإدراك البصري\" و\"الإجراءات القابلة للتنفيذ\" ويوفر أساسًا تقنيًا موحدًا للوكلاء متعدد الوسائط في سيناريوهات الأعمال الواقعية. يتم تمديد نافذة السياق البصري إلى 128 ألف، مما يدعم معالجة تدفقات الفيديو الطويلة وتحليل الصور المتعددة عالية الدقة.",
"zai/glm-4.5-air.description": "GLM-4.5 وGLM-4.5-Air هما أحدث النماذج الرائدة لدينا لتطبيقات الوكلاء، وكلاهما يستخدم بنية MoE. يحتوي GLM-4.5 على 355 مليار إجمالي و32 مليار نشط لكل تمرير؛ بينما GLM-4.5-Air أنحف بإجمالي 106 مليار و12 مليار نشط.",
"zai/glm-4.5.description": "سلسلة GLM-4.5 مصممة للوكلاء. النموذج الرائد GLM-4.5 يجمع بين الاستدلال، والبرمجة، ومهارات الوكلاء مع 355 مليار معلمة إجمالية (32 مليار نشطة) ويقدّم أوضاع تشغيل مزدوجة كنظام استدلال هجين.",
"zai/glm-4.5v.description": "GLM-4.5V مبني على GLM-4.5-Air، ويَرِث تقنيات GLM-4.1V-Thinking المثبتة، ويتوسع ببنية MoE قوية بسعة 106 مليار.",
+1 -1
View File
@@ -1,6 +1,7 @@
{
"arguments.moreParams": "إجمالي {{count}} من المعاملات",
"arguments.title": "المعلمات",
"builtins.lobe-activator.apiName.activateTools": "تفعيل الأدوات",
"builtins.lobe-agent-builder.apiName.getAvailableModels": "الحصول على النماذج المتاحة",
"builtins.lobe-agent-builder.apiName.getAvailableTools": "الحصول على المهارات المتاحة",
"builtins.lobe-agent-builder.apiName.getConfig": "الحصول على الإعدادات",
@@ -209,7 +210,6 @@
"builtins.lobe-skills.apiName.runCommand": "تشغيل الأمر",
"builtins.lobe-skills.apiName.searchSkill": "البحث عن المهارات",
"builtins.lobe-skills.title": "المهارات",
"builtins.lobe-tools.apiName.activateTools": "تفعيل الأدوات",
"builtins.lobe-topic-reference.apiName.getTopicContext": "الحصول على سياق الموضوع",
"builtins.lobe-topic-reference.title": "مرجع الموضوع",
"builtins.lobe-user-memory.apiName.addContextMemory": "إضافة ذاكرة السياق",
+6 -1
View File
@@ -8,6 +8,7 @@
"azure.description": "تقدم Azure نماذج ذكاء اصطناعي متقدمة، بما في ذلك سلسلة GPT-3.5 وGPT-4، لمعالجة أنواع بيانات متنوعة ومهام معقدة مع التركيز على الأمان والموثوقية والاستدامة.",
"azureai.description": "توفر Azure نماذج ذكاء اصطناعي متقدمة، بما في ذلك سلسلة GPT-3.5 وGPT-4، لمعالجة أنواع بيانات متنوعة ومهام معقدة مع التركيز على الأمان والموثوقية والاستدامة.",
"baichuan.description": "تركز Baichuan AI على النماذج الأساسية ذات الأداء القوي في المعرفة الصينية، ومعالجة السياقات الطويلة، والتوليد الإبداعي. تم تحسين نماذجها (Baichuan 4 وBaichuan 3 Turbo وBaichuan 3 Turbo 128k) لسيناريوهات مختلفة وتقدم قيمة عالية.",
"bailiancodingplan.description": "خطة الترميز علي بابليون هي خدمة ذكاء اصطناعي متخصصة توفر الوصول إلى نماذج محسّنة للترميز من Qwen وGLM وKimi وMiniMax عبر نقطة نهاية مخصصة.",
"bedrock.description": "توفر Amazon Bedrock للمؤسسات نماذج لغوية وبصرية متقدمة، بما في ذلك Anthropic Claude وMeta Llama 3.1، بدءًا من الخيارات الخفيفة إلى عالية الأداء لمهام النصوص والدردشة والصور.",
"bfl.description": "مختبر أبحاث رائد في مجال الذكاء الاصطناعي المتقدم، يعمل على بناء البنية التحتية البصرية للمستقبل.",
"cerebras.description": "Cerebras هي منصة استدلال تعتمد على نظام CS-3، تركز على تقديم خدمات نماذج لغوية كبيرة بزمن استجابة منخفض جدًا وسرعة عالية لمهام الوقت الحقيقي مثل توليد الأكواد والمهام التفاعلية.",
@@ -21,6 +22,7 @@
"giteeai.description": "توفر Gitee AI واجهات برمجة تطبيقات بدون خوادم لخدمات استدلال النماذج اللغوية الكبيرة، جاهزة للاستخدام من قبل المطورين.",
"github.description": "مع نماذج GitHub، يمكن للمطورين العمل كمهندسي ذكاء اصطناعي باستخدام نماذج رائدة في الصناعة.",
"githubcopilot.description": "يمكنك الوصول إلى نماذج Claude وGPT وGemini من خلال اشتراكك في GitHub Copilot.",
"glmcodingplan.description": "خطة الترميز GLM توفر الوصول إلى نماذج الذكاء الاصطناعي Zhipu بما في ذلك GLM-5 وGLM-4.7 لأداء مهام الترميز عبر اشتراك ثابت الرسوم.",
"google.description": "عائلة Gemini من Google هي أكثر نماذج الذكاء الاصطناعي تطورًا للأغراض العامة، تم تطويرها بواسطة Google DeepMind للاستخدام متعدد الوسائط عبر النصوص والرموز والصور والصوت والفيديو. يمكن تشغيلها من مراكز البيانات إلى الأجهزة المحمولة بكفاءة عالية وانتشار واسع.",
"groq.description": "توفر محركات الاستدلال LPU من Groq أداءً متميزًا في المعايير مع سرعة وكفاءة استثنائية، مما يضع معيارًا عاليًا للاستدلال منخفض الكمون في السحابة.",
"higress.description": "Higress هو بوابة API سحابية أصلية تم تطويرها داخل Alibaba لمعالجة تأثير إعادة تحميل Tengine على الاتصالات طويلة الأمد وسد الفجوات في موازنة تحميل gRPC/Dubbo.",
@@ -29,10 +31,12 @@
"infiniai.description": "توفر خدمات نماذج لغوية كبيرة عالية الأداء وسهلة الاستخدام وآمنة لمطوري التطبيقات، تغطي كامل دورة العمل من تطوير النموذج إلى نشره في الإنتاج.",
"internlm.description": "منظمة مفتوحة المصدر تركز على أبحاث النماذج الكبيرة والأدوات، وتوفر منصة فعالة وسهلة الاستخدام تتيح الوصول إلى أحدث النماذج والخوارزميات.",
"jina.description": "تأسست Jina AI في عام 2020، وهي شركة رائدة في مجال البحث الذكي. تشمل تقنياتها نماذج المتجهات، ومعيدو الترتيب، ونماذج لغوية صغيرة لبناء تطبيقات بحث توليدية ومتعددة الوسائط عالية الجودة.",
"kimicodingplan.description": "كود Kimi من Moonshot AI يوفر الوصول إلى نماذج Kimi بما في ذلك K2.5 لأداء مهام الترميز.",
"lmstudio.description": "LM Studio هو تطبيق سطح مكتب لتطوير وتجربة النماذج اللغوية الكبيرة على جهازك.",
"lobehub.description": "يستخدم LobeHub Cloud واجهات برمجة التطبيقات الرسمية للوصول إلى نماذج الذكاء الاصطناعي ويقيس الاستخدام باستخدام أرصدة مرتبطة برموز النماذج.",
"lobehub.description": "LobeHub Cloud يستخدم واجهات برمجية رسمية للوصول إلى نماذج الذكاء الاصطناعي ويقيس الاستخدام عبر أرصدة مرتبطة برموز النماذج.",
"longcat.description": "LongCat هو سلسلة من نماذج الذكاء الاصطناعي التوليدية الكبيرة التي تم تطويرها بشكل مستقل بواسطة Meituan. تم تصميمه لتعزيز إنتاجية المؤسسة الداخلية وتمكين التطبيقات المبتكرة من خلال بنية حسابية فعالة وقدرات متعددة الوسائط قوية.",
"minimax.description": "تأسست MiniMax في عام 2021، وتبني نماذج ذكاء اصطناعي متعددة الوسائط للأغراض العامة، بما في ذلك نماذج نصية بمليارات المعلمات، ونماذج صوتية وبصرية، بالإضافة إلى تطبيقات مثل Hailuo AI.",
"minimaxcodingplan.description": "خطة الرموز MiniMax توفر الوصول إلى نماذج MiniMax بما في ذلك M2.7 لأداء مهام الترميز عبر اشتراك ثابت الرسوم.",
"mistral.description": "تقدم Mistral نماذج متقدمة عامة ومتخصصة وبحثية للتفكير المعقد، والمهام متعددة اللغات، وتوليد الأكواد، مع دعم استدعاء الوظائف للتكامل المخصص.",
"modelscope.description": "ModelScope هي منصة نماذج كخدمة من Alibaba Cloud، تقدم مجموعة واسعة من النماذج وخدمات الاستدلال.",
"moonshot.description": "تقدم Moonshot، من Moonshot AI (شركة Beijing Moonshot Technology)، نماذج معالجة لغة طبيعية متعددة لحالات استخدام مثل إنشاء المحتوى، والبحث، والتوصيات، والتحليل الطبي، مع دعم قوي للسياقات الطويلة والتوليد المعقد.",
@@ -65,6 +69,7 @@
"vertexai.description": "عائلة Gemini من Google هي أكثر نماذج الذكاء الاصطناعي تطورًا للأغراض العامة، تم تطويرها بواسطة Google DeepMind للاستخدام متعدد الوسائط عبر النصوص والرموز والصور والصوت والفيديو. يمكن تشغيلها من مراكز البيانات إلى الأجهزة المحمولة، مما يعزز الكفاءة ومرونة النشر.",
"vllm.description": "vLLM مكتبة سريعة وسهلة الاستخدام لاستدلال وخدمة النماذج اللغوية الكبيرة.",
"volcengine.description": "توفر منصة نماذج ByteDance وصولًا آمنًا وغنيًا بالميزات وفعالًا من حيث التكلفة إلى النماذج، بالإضافة إلى أدوات شاملة للبيانات، والتخصيص، والاستدلال، والتقييم.",
"volcenginecodingplan.description": "خطة الترميز Volcengine من ByteDance توفر الوصول إلى نماذج ترميز متعددة بما في ذلك Doubao-Seed-Code وGLM-4.7 وDeepSeek-V3.2 وKimi-K2.5 عبر اشتراك ثابت الرسوم.",
"wenxin.description": "منصة متكاملة للمؤسسات لتطوير النماذج الأساسية والتطبيقات الذكية، تقدم أدوات شاملة لسير عمل النماذج التوليدية وتطبيقاتها.",
"xai.description": "تقوم xAI ببناء ذكاء اصطناعي لتسريع الاكتشاف العلمي، بهدف تعميق فهم البشرية للكون.",
"xiaomimimo.description": "تقدم Xiaomi MiMo خدمة نموذج محادثة متوافقة مع واجهة برمجة تطبيقات OpenAI. يدعم نموذج mimo-v2-flash التفكير العميق، الإخراج المتدفق، استدعاء الوظائف، نافذة سياق بسعة 256 ألف، وإخراجًا أقصى يصل إلى 128 ألف.",
+65
View File
@@ -193,6 +193,70 @@
"analytics.title": "التحليلات",
"checking": "جارٍ التحقق...",
"checkingPermissions": "جارٍ التحقق من الأذونات...",
"creds.actions.delete": "حذف",
"creds.actions.deleteConfirm.cancel": "إلغاء",
"creds.actions.deleteConfirm.content": "سيتم حذف بيانات الاعتماد هذه بشكل دائم. لا يمكن التراجع عن هذا الإجراء.",
"creds.actions.deleteConfirm.ok": "حذف",
"creds.actions.deleteConfirm.title": "حذف بيانات الاعتماد؟",
"creds.actions.edit": "تعديل",
"creds.actions.view": "عرض",
"creds.create": "بيانات اعتماد جديدة",
"creds.createModal.fillForm": "املأ التفاصيل",
"creds.createModal.selectType": "اختر النوع",
"creds.createModal.title": "إنشاء بيانات اعتماد",
"creds.edit.title": "تعديل بيانات الاعتماد",
"creds.empty": "لم يتم تكوين أي بيانات اعتماد حتى الآن",
"creds.file.authRequired": "يرجى تسجيل الدخول إلى السوق أولاً",
"creds.file.uploadFailed": "فشل تحميل الملف",
"creds.file.uploadSuccess": "تم تحميل الملف بنجاح",
"creds.file.uploading": "جارٍ التحميل...",
"creds.form.addPair": "إضافة زوج مفتاح-قيمة",
"creds.form.back": "رجوع",
"creds.form.cancel": "إلغاء",
"creds.form.connectionRequired": "يرجى اختيار اتصال OAuth",
"creds.form.description": "الوصف",
"creds.form.descriptionPlaceholder": "وصف اختياري لهذه البيانات",
"creds.form.file": "ملف بيانات الاعتماد",
"creds.form.fileRequired": "يرجى تحميل ملف",
"creds.form.key": "المعرف",
"creds.form.keyPattern": "يمكن أن يحتوي المعرف فقط على أحرف وأرقام وشرطات سفلية وشرطات",
"creds.form.keyRequired": "المعرف مطلوب",
"creds.form.name": "اسم العرض",
"creds.form.nameRequired": "اسم العرض مطلوب",
"creds.form.save": "حفظ",
"creds.form.selectConnection": "اختر اتصال OAuth",
"creds.form.selectConnectionPlaceholder": "اختر حسابًا متصلاً",
"creds.form.selectedFile": "الملف المحدد",
"creds.form.submit": "إنشاء",
"creds.form.uploadDesc": "يدعم تنسيقات ملفات JSON وPEM وغيرها من ملفات بيانات الاعتماد",
"creds.form.uploadHint": "انقر أو اسحب الملف لتحميله",
"creds.form.valuePlaceholder": "أدخل القيمة",
"creds.form.values": "أزواج المفتاح-القيمة",
"creds.oauth.noConnections": "لا توجد اتصالات OAuth متاحة. يرجى توصيل حساب أولاً.",
"creds.signIn": "تسجيل الدخول إلى السوق",
"creds.signInRequired": "يرجى تسجيل الدخول إلى السوق لإدارة بيانات الاعتماد الخاصة بك",
"creds.table.actions": "الإجراءات",
"creds.table.key": "المعرف",
"creds.table.lastUsed": "آخر استخدام",
"creds.table.name": "الاسم",
"creds.table.neverUsed": "لم يتم الاستخدام",
"creds.table.preview": "معاينة",
"creds.table.type": "النوع",
"creds.typeDesc.file": "تحميل ملفات بيانات الاعتماد مثل حسابات الخدمة أو الشهادات",
"creds.typeDesc.kv-env": "تخزين مفاتيح API والرموز كمتغيرات بيئية",
"creds.typeDesc.kv-header": "تخزين قيم التفويض كعناوين HTTP",
"creds.typeDesc.oauth": "ربط باتصال OAuth موجود",
"creds.types.all": "الكل",
"creds.types.file": "ملف",
"creds.types.kv-env": "بيئة",
"creds.types.kv-header": "رأس",
"creds.types.oauth": "OAuth",
"creds.view.error": "فشل في تحميل بيانات الاعتماد",
"creds.view.noValues": "لا توجد قيم",
"creds.view.oauthNote": "يتم إدارة بيانات اعتماد OAuth بواسطة الخدمة المتصلة.",
"creds.view.title": "عرض بيانات الاعتماد: {{name}}",
"creds.view.values": "قيم بيانات الاعتماد",
"creds.view.warning": "هذه القيم حساسة. لا تشاركها مع الآخرين.",
"danger.clear.action": "مسح الآن",
"danger.clear.confirm": "هل تريد مسح جميع بيانات الدردشة؟ لا يمكن التراجع عن هذا الإجراء.",
"danger.clear.desc": "سيتم حذف جميع البيانات، بما في ذلك الوكلاء والملفات والرسائل والمهارات. لن يتم حذف حسابك.",
@@ -731,6 +795,7 @@
"tab.appearance": "المظهر",
"tab.chatAppearance": "مظهر المحادثة",
"tab.common": "المظهر",
"tab.creds": "بيانات الاعتماد",
"tab.experiment": "تجريبي",
"tab.hotkey": "اختصارات لوحة المفاتيح",
"tab.image": "خدمة توليد الصور",
+5
View File
@@ -199,6 +199,8 @@
"plans.btn.paymentDesc": "يدعم بطاقات الائتمان / Alipay / WeChat Pay",
"plans.btn.paymentDescForZarinpal": "يدعم بطاقات الائتمان",
"plans.btn.soon": "قريبًا",
"plans.cancelDowngrade": "إلغاء التخفيض المجدول",
"plans.cancelDowngradeSuccess": "تم إلغاء التخفيض المجدول",
"plans.changePlan": "اختر خطة",
"plans.cloud.history": "سجل محادثات غير محدود",
"plans.cloud.sync": "مزامنة سحابية عالمية",
@@ -215,6 +217,7 @@
"plans.current": "الخطة الحالية",
"plans.downgradePlan": "خطة التخفيض المستهدفة",
"plans.downgradeTip": "لقد قمت بالفعل بتغيير الاشتراك. لا يمكنك تنفيذ عمليات أخرى حتى يكتمل التبديل",
"plans.downgradeWillCancel": "سيؤدي هذا الإجراء إلى إلغاء تخفيض الخطة المجدول",
"plans.embeddingStorage.embeddings": "مدخلات",
"plans.embeddingStorage.title": "تخزين المتجهات",
"plans.embeddingStorage.tooltip": "تنتج صفحة مستند واحدة (1000-1500 حرف) حوالي إدخال متجه واحد. (تقدير باستخدام OpenAI Embeddings، وقد يختلف حسب النموذج)",
@@ -253,6 +256,7 @@
"plans.payonce.ok": "تأكيد الاختيار",
"plans.payonce.popconfirm": "بعد الدفع لمرة واحدة، يجب الانتظار حتى انتهاء الاشتراك لتغيير الخطة أو دورة الفوترة. يرجى تأكيد اختيارك.",
"plans.payonce.tooltip": "يتطلب الدفع لمرة واحدة الانتظار حتى انتهاء الاشتراك لتغيير الخطة أو دورة الفوترة",
"plans.pendingDowngrade": "تخفيض قيد الانتظار",
"plans.plan.enterprise.contactSales": "اتصل بالمبيعات",
"plans.plan.enterprise.title": "الشركات",
"plans.plan.free.desc": "للمستخدمين الجدد",
@@ -366,6 +370,7 @@
"summary.title": "ملخص الفوترة",
"summary.usageThisMonth": "عرض استخدامك هذا الشهر.",
"summary.viewBillingHistory": "عرض سجل المدفوعات",
"switchDowngradeTarget": "تغيير هدف التخفيض",
"switchPlan": "تبديل الخطة",
"switchToMonthly.desc": "بعد التبديل، ستبدأ الفوترة الشهرية بعد انتهاء الخطة السنوية الحالية.",
"switchToMonthly.title": "التبديل إلى الفوترة الشهرية",
+37 -1
View File
@@ -1,5 +1,6 @@
{
"channel.appSecret": "Секрет на приложението",
"channel.appSecretHint": "Тайният ключ на вашето бот приложение. Той ще бъде криптиран и съхранен сигурно.",
"channel.appSecretPlaceholder": "Поставете вашия секрет на приложението тук",
"channel.applicationId": "ID на приложението / Потребителско име на бота",
"channel.applicationIdHint": "Уникален идентификатор за вашето бот приложение.",
@@ -9,14 +10,31 @@
"channel.botTokenHowToGet": "Как да го получите?",
"channel.botTokenPlaceholderExisting": "Токенът е скрит за сигурност",
"channel.botTokenPlaceholderNew": "Поставете вашия токен на бота тук",
"channel.charLimit": "Ограничение на символите",
"channel.charLimitHint": "Максимален брой символи на съобщение",
"channel.connectFailed": "Свързването на бота не успя",
"channel.connectSuccess": "Ботът е успешно свързан",
"channel.connecting": "Свързване...",
"channel.connectionConfig": "Конфигурация на връзката",
"channel.copied": "Копирано в клипборда",
"channel.copy": "Копирай",
"channel.credentials": "Удостоверения",
"channel.debounceMs": "Прозорец за обединяване на съобщения (ms)",
"channel.debounceMsHint": "Колко време да се изчака за допълнителни съобщения преди изпращане към агента (ms)",
"channel.deleteConfirm": "Сигурни ли сте, че искате да премахнете този канал?",
"channel.deleteConfirmDesc": "Това действие ще премахне окончателно този канал за съобщения и неговата конфигурация. Това не може да бъде отменено.",
"channel.devWebhookProxyUrl": "HTTPS тунел URL",
"channel.devWebhookProxyUrlHint": "По избор. HTTPS тунел URL за пренасочване на заявки за уебхук към локален dev сървър.",
"channel.disabled": "Деактивиран",
"channel.discord.description": "Свържете този асистент с Discord сървър за канален чат и директни съобщения.",
"channel.dm": "Директни съобщения",
"channel.dmEnabled": "Активиране на директни съобщения",
"channel.dmEnabledHint": "Позволете на бота да получава и отговаря на директни съобщения",
"channel.dmPolicy": "Политика за директни съобщения",
"channel.dmPolicyAllowlist": "Списък с позволени",
"channel.dmPolicyDisabled": "Деактивирано",
"channel.dmPolicyHint": "Контролирайте кой може да изпраща директни съобщения до бота",
"channel.dmPolicyOpen": "Отворено",
"channel.documentation": "Документация",
"channel.enabled": "Активиран",
"channel.encryptKey": "Ключ за криптиране",
@@ -26,6 +44,7 @@
"channel.endpointUrlHint": "Моля, копирайте този URL и го поставете в полето <bold>{{fieldName}}</bold> в {{name}} Developer Portal.",
"channel.feishu.description": "Свържете този асистент с Feishu за лични и групови чатове.",
"channel.lark.description": "Свържете този асистент с Lark за лични и групови чатове.",
"channel.openPlatform": "Отворена платформа",
"channel.platforms": "Платформи",
"channel.publicKey": "Публичен ключ",
"channel.publicKeyHint": "По избор. Използва се за проверка на заявки за взаимодействие от Discord.",
@@ -42,6 +61,16 @@
"channel.secretToken": "Секретен токен на уебхук",
"channel.secretTokenHint": "По избор. Използва се за проверка на заявки за уебхук от Telegram.",
"channel.secretTokenPlaceholder": "По избор секрет за проверка на уебхук",
"channel.settings": "Разширени настройки",
"channel.settingsResetConfirm": "Сигурни ли сте, че искате да върнете разширените настройки към техните стойности по подразбиране?",
"channel.settingsResetDefault": "Връщане към стойности по подразбиране",
"channel.setupGuide": "Ръководство за настройка",
"channel.showUsageStats": "Показване на статистики за използване",
"channel.showUsageStatsHint": "Показване на статистики за използване на токени, разходи и продължителност в отговорите на бота",
"channel.signingSecret": "Тайна за подписване",
"channel.signingSecretHint": "Използва се за проверка на заявки към уебхук.",
"channel.slack.appIdHint": "Вашият Slack App ID от таблото за управление на Slack API (започва с A).",
"channel.slack.description": "Свържете този асистент със Slack за разговори в канали и директни съобщения.",
"channel.telegram.description": "Свържете този асистент с Telegram за лични и групови чатове.",
"channel.testConnection": "Тестване на връзката",
"channel.testFailed": "Тестът на връзката неуспешен",
@@ -50,5 +79,12 @@
"channel.validationError": "Моля, попълнете ID на приложението и токен",
"channel.verificationToken": "Токен за проверка",
"channel.verificationTokenHint": "По избор. Използва се за проверка на източника на събития за уебхук.",
"channel.verificationTokenPlaceholder": "Поставете вашия токен за проверка тук"
"channel.verificationTokenPlaceholder": "Поставете вашия токен за проверка тук",
"channel.wechat.description": "Свържете този асистент с WeChat чрез iLink Bot за лични и групови чатове.",
"channel.wechatQrExpired": "QR кодът е изтекъл. Моля, обновете, за да получите нов.",
"channel.wechatQrRefresh": "Обновяване на QR код",
"channel.wechatQrScaned": "QR кодът е сканиран. Моля, потвърдете влизането в WeChat.",
"channel.wechatQrWait": "Отворете WeChat и сканирайте QR кода, за да се свържете.",
"channel.wechatScanTitle": "Свързване на WeChat бот",
"channel.wechatScanToConnect": "Сканирайте QR кода, за да се свържете"
}
+3 -1
View File
@@ -397,7 +397,6 @@
"sync.status.unconnected": "Неуспешна връзка",
"sync.title": "Статус на синхронизация",
"sync.unconnected.tip": "Неуспешна връзка със сървъра за сигнализация, не може да се установи P2P комуникация. Моля, проверете мрежата и опитайте отново.",
"tab.aiImage": "Изкуство",
"tab.audio": "Аудио",
"tab.chat": "Чат",
"tab.community": "Общност",
@@ -405,6 +404,7 @@
"tab.eval": "Оценителна лаборатория",
"tab.files": "Файлове",
"tab.home": "Начало",
"tab.image": "Изображение",
"tab.knowledgeBase": "Библиотека",
"tab.marketplace": "Пазар",
"tab.me": "Аз",
@@ -432,6 +432,7 @@
"userPanel.billing": "Управление на плащания",
"userPanel.cloud": "Стартирай {{name}}",
"userPanel.community": "Общност",
"userPanel.credits": "Управление на кредити",
"userPanel.data": "Съхранение на данни",
"userPanel.defaultNickname": "Потребител от общността",
"userPanel.discord": "Поддръжка в общността",
@@ -443,6 +444,7 @@
"userPanel.plans": "Абонаментни планове",
"userPanel.profile": "Акаунт",
"userPanel.setting": "Настройки",
"userPanel.upgradePlan": "Надграждане на плана",
"userPanel.usages": "Статистика на използване",
"version": "Версия"
}
+5
View File
@@ -83,6 +83,11 @@
"preference.empty": "Няма налични спомени за предпочитания",
"preference.source": "Източник",
"preference.suggestions": "Действия, които агентът може да предприеме",
"purge.action": "Изчисти всичко",
"purge.confirm": "Сигурни ли сте, че искате да изтриете всички спомени? Това ще премахне всички записи на спомени завинаги и не може да бъде отменено.",
"purge.error": "Неуспешно изчистване на спомените. Моля, опитайте отново.",
"purge.success": "Всички спомени са изтрити.",
"purge.title": "Изчисти всички спомени",
"tab.activities": "Дейности",
"tab.contexts": "Контексти",
"tab.experiences": "Изживявания",
+2
View File
@@ -231,6 +231,8 @@
"providerModels.item.modelConfig.extendParams.options.imageResolution.hint": "За моделите Gemini 3 за генериране на изображения; контролира резолюцията на генерираните изображения.",
"providerModels.item.modelConfig.extendParams.options.imageResolution2.hint": "За модели Gemini 3.1 Flash Image; контролира резолюцията на генерираните изображения (поддържа 512px).",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken.hint": "За Claude, Qwen3 и подобни; контролира бюджета от токени за разсъждение.",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken32k.hint": "За GLM-5 и GLM-4.7; контролира бюджета за токени за разсъждение (максимум 32k).",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken80k.hint": "За серията Qwen3; контролира бюджета за токени за разсъждение (максимум 80k).",
"providerModels.item.modelConfig.extendParams.options.reasoningEffort.hint": "За OpenAI и други модели с логическо мислене; контролира усилието за разсъждение.",
"providerModels.item.modelConfig.extendParams.options.textVerbosity.hint": "За серията GPT-5+; контролира обемността на изходния текст.",
"providerModels.item.modelConfig.extendParams.options.thinking.hint": "За някои модели Doubao; позволява на модела да реши дали да мисли задълбочено.",
+40 -32
View File
@@ -53,7 +53,14 @@
"FLUX.1-Kontext-dev.description": "FLUX.1-Kontext-dev е мултимодален модел за генериране и редактиране на изображения от Black Forest Labs, базиран на архитектура Rectified Flow Transformer с 12B параметъра. Фокусира се върху генериране, реконструкция, подобрение и редакция на изображения според зададен контекст. Комбинира контролираната генерация на дифузионни модели с контекстното моделиране на Transformer, поддържайки висококачествени резултати за задачи като inpainting, outpainting и реконструкция на визуални сцени.",
"FLUX.1-Kontext-pro.description": "FLUX.1 Kontext [pro]",
"FLUX.1-dev.description": "FLUX.1-dev е мултимодален езиков модел с отворен код (MLLM) от Black Forest Labs, оптимизиран за задачи с изображения и текст, комбиниращ разбиране и генериране на изображения/текст. Изграден върху напреднали LLM модели (като Mistral-7B), използва внимателно проектиран визуален енкодер и многоетапна настройка с инструкции за постигане на мултимодална координация и логическо мислене при сложни задачи.",
"GLM-4.5-Air.description": "GLM-4.5-Air: Олекотена версия за бързи отговори.",
"GLM-4.5.description": "GLM-4.5: Високопроизводителен модел за разсъждения, програмиране и задачи с агенти.",
"GLM-4.6.description": "GLM-4.6: Модел от предишно поколение.",
"GLM-4.7.description": "GLM-4.7 е най-новият водещ модел на Zhipu, подобрен за сценарии на агентно програмиране с усъвършенствани възможности за кодиране, дългосрочно планиране на задачи и сътрудничество с инструменти.",
"GLM-5-Turbo.description": "GLM-5-Turbo: Оптимизирана версия на GLM-5 с по-бързо извеждане за задачи по програмиране.",
"GLM-5.description": "GLM-5 е водещ модел от следващо поколение на Zhipu, създаден за агентно инженерство. Той осигурява надеждна продуктивност в сложни системни инженерни задачи и дългосрочни агентни задачи. В областта на програмирането и агентните способности GLM-5 постига най-добри резултати сред моделите с отворен код.",
"Gryphe/MythoMax-L2-13b.description": "MythoMax-L2 (13B) е иновативен модел за разнообразни области и сложни задачи.",
"HY-Image-V3.0.description": "Мощни възможности за извличане на характеристики от оригиналното изображение и запазване на детайлите, предоставящи по-богата визуална текстура и създаващи високоточни, добре композирани, продукционни визуализации.",
"HelloMeme.description": "HelloMeme е AI инструмент, който генерира мемета, GIF-ове или кратки видеа от предоставени изображения или движения. Не изисква умения за рисуване или програмиране — само референтно изображение — за създаване на забавно, атрактивно и стилово консистентно съдържание.",
"HiDream-E1-Full.description": "HiDream-E1-Full е модел за отворен код за мултимодално редактиране на изображения от HiDream.ai, базиран на усъвършенствана архитектура Diffusion Transformer и силно езиково разбиране (вграден LLaMA 3.1-8B-Instruct). Той поддържа генериране на изображения, трансфер на стилове, локални редакции и прерисуване, управлявани от естествен език, с отлично разбиране и изпълнение на текст и изображения.",
"HiDream-I1-Full.description": "HiDream-I1 е нов модел за генериране на изображения с отворен код, пуснат от HiDream. С 17 милиарда параметри (Flux има 12 милиарда), той може да предостави водещо в индустрията качество на изображенията за секунди.",
@@ -84,14 +91,14 @@
"MiniMax-M2.1-highspeed.description": "Мощни многоезични програмни възможности с по-бързо и ефективно извеждане.",
"MiniMax-M2.1.description": "MiniMax-M2.1 е водеща отворена голяма езикова система от MiniMax, фокусирана върху решаването на сложни реални задачи. Основните ѝ предимства са възможностите за програмиране на множество езици и способността да действа като агент за решаване на сложни задачи.",
"MiniMax-M2.5-Lightning.description": "M2.5 Lightning: Същата производителност, по-бърз и по-агилен (приблизително 100 tps).",
"MiniMax-M2.5-highspeed.description": "Същата производителност като M2.5, но с значително по-бързо извеждане.",
"MiniMax-M2.5-highspeed.description": "MiniMax M2.5 Highspeed: Същата производителност като M2.5, но с по-бързо извеждане.",
"MiniMax-M2.5.description": "MiniMax-M2.5 е водещ модел с отворен код от MiniMax, фокусиран върху решаването на сложни реални задачи. Основните му предимства са мултиезиковите програмни възможности и способността да решава сложни задачи като агент.",
"MiniMax-M2.7-highspeed.description": "Същата производителност като M2.7, но със значително по-бързо извеждане (~100 tps).",
"MiniMax-M2.7.description": "Първият саморазвиващ се модел с първокласна производителност в кодирането и агентните задачи (~60 tps).",
"MiniMax-M2.description": "Създаден специално за ефективно програмиране и работни потоци с агенти",
"MiniMax-M2.7-highspeed.description": "MiniMax M2.7 Highspeed: Същата производителност като M2.7, но със значително по-бързо извеждане.",
"MiniMax-M2.7.description": "MiniMax M2.7: Начало на пътя към рекурсивно самоусъвършенстване, водещи инженерни способности в реалния свят.",
"MiniMax-M2.description": "MiniMax M2: Модел от предишно поколение.",
"MiniMax-Text-01.description": "MiniMax-01 въвежда мащабно линейно внимание отвъд класическите трансформери, с 456B параметри и 45.9B активирани на преминаване. Постига водеща производителност и поддържа до 4M токена контекст (32× GPT-4o, 20× Claude-3.5-Sonnet).",
"MiniMaxAI/MiniMax-M1-80k.description": "MiniMax-M1 е отворен модел с голям мащаб и хибридно внимание, с общо 456B параметри и ~45.9B активни на токен. Поддържа нативно 1M контекст и използва Flash Attention за 75% по-малко FLOPs при генериране на 100K токена спрямо DeepSeek R1. С MoE архитектура, CISPO и хибридно обучение с внимание и RL, постига водеща производителност при дълги входове и реални задачи по софтуерно инженерство.",
"MiniMaxAI/MiniMax-M2.description": "MiniMax-M2 преосмисля ефективността на агентите. Това е компактен, бърз и икономичен MoE модел с 230B общо и 10B активни параметри, създаден за водещи задачи по програмиране и агенти, като същевременно запазва силен общ интелект. Със само 10B активни параметри, съперничи на много по-големи модели, което го прави идеален за приложения с висока ефективност.",
"MiniMaxAI/MiniMax-M1-80k.description": "MiniMax-M1 е модел за хибридно внимание с отворени тегла, съдържащ 456 милиарда общи параметри и ~45.9 милиарда активни на токен. Той поддържа контекст от 1 милион токена и използва Flash Attention за намаляване на FLOPs с 75% при генериране на 100K токена спрямо DeepSeek R1. С архитектура MoE плюс CISPO и обучение с хибридно внимание RL, той постига водещи резултати в задачи за дългосрочно разсъждение и реално софтуерно инженерство.",
"MiniMaxAI/MiniMax-M2.description": "MiniMax-M2 преосмисля ефективността на агентите. Това е компактен, бърз и икономичен модел MoE с 230 милиарда общи и 10 милиарда активни параметри, създаден за водещи задачи по програмиране и агенти, като същевременно запазва силен общ интелект. Със само 10 милиарда активни параметри, той съперничи на много по-големи модели, което го прави идеален за приложения с висока ефективност.",
"Moonshot-Kimi-K2-Instruct.description": "1T общи параметри с 32B активни. Сред немислещите модели е водещ в гранични знания, математика и програмиране, и по-силен в общи агентски задачи. Оптимизиран за агентски натоварвания, може да предприема действия, а не само да отговаря на въпроси. Най-подходящ за импровизационен, общ чат и агентски преживявания като модел на рефлексно ниво без дълго мислене.",
"NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO.description": "Nous Hermes 2 - Mixtral 8x7B-DPO (46.7B) е високоточен модел с инструкции за сложни изчисления.",
"OmniConsistency.description": "OmniConsistency подобрява стиловата последователност и обобщението при задачи от изображение към изображение чрез въвеждане на мащабни дифузионни трансформери (DiTs) и сдвоени стилизирани данни, избягвайки влошаване на стила.",
@@ -105,14 +112,14 @@
"Phi-3.5-mini-instruct.description": "Актуализирана версия на модела Phi-3-mini.",
"Phi-3.5-vision-instrust.description": "Актуализирана версия на модела Phi-3-vision.",
"Pro/MiniMaxAI/MiniMax-M2.1.description": "MiniMax-M2.1 е отворен модел с голям езиков капацитет, оптимизиран за агентни способности, с изключителни резултати в програмиране, използване на инструменти, следване на инструкции и дългосрочно планиране. Моделът поддържа многоезична разработка на софтуер и изпълнение на сложни многoетапни работни потоци, постигайки резултат от 74.0 в SWE-bench Verified и надминава Claude Sonnet 4.5 в многоезични сценарии.",
"Pro/MiniMaxAI/MiniMax-M2.5.description": "MiniMax-M2.5 е най-новият голям езиков модел, разработен от MiniMax, обучен чрез мащабно подсилващо обучение в стотици хиляди сложни реални среди. С архитектура MoE и 229 милиарда параметри, той постига водещи в индустрията резултати в задачи като програмиране, извикване на инструменти от агенти, търсене и офис сценарии.",
"Pro/MiniMaxAI/MiniMax-M2.5.description": "MiniMax-M2.5 е най-новият голям езиков модел, разработен от MiniMax, обучен чрез мащабно обучение с подсилване в стотици хиляди сложни, реални среди. С архитектура MoE и 229 милиарда параметри, той постига водещи резултати в задачи като програмиране, използване на инструменти от агенти, търсене и офис сценарии.",
"Pro/Qwen/Qwen2-7B-Instruct.description": "Qwen2-7B-Instruct е 7B модел с инструкции от серията Qwen2. Използва трансформерна архитектура със SwiGLU, QKV bias и групирано внимание, и обработва големи входове. Постига отлични резултати в езиково разбиране, генериране, многоезични задачи, програмиране, математика и разсъждение, надминавайки повечето отворени модели и конкурирайки се със затворени.",
"Pro/Qwen/Qwen2.5-7B-Instruct.description": "Qwen2.5-7B-Instruct е част от най-новата серия LLM на Alibaba Cloud. Моделът с 7B параметри носи значителни подобрения в програмирането и математиката, поддържа над 29 езика и подобрява следването на инструкции, разбирането на структурирани данни и генерирането на структурирани изходи (особено JSON).",
"Pro/Qwen/Qwen2.5-Coder-7B-Instruct.description": "Qwen2.5-Coder-7B-Instruct е най-новият LLM на Alibaba Cloud, фокусиран върху програмиране. Изграден върху Qwen2.5 и обучен с 5.5T токена, значително подобрява генерирането на код, разсъждението и поправката, като същевременно запазва силни математически и общи способности, осигурявайки стабилна основа за кодови агенти.",
"Pro/Qwen/Qwen2.5-VL-7B-Instruct.description": "Qwen2.5-VL е нов модел за визия и език от серията Qwen с мощно визуално разбиране. Анализира текст, графики и оформления в изображения, разбира дълги видеа и събития, поддържа разсъждение и използване на инструменти, обвързване на обекти във формати, и структурирани изходи. Подобрява динамичната резолюция и обучението с честота на кадрите за видео разбиране и повишава ефективността на визуалния енкодер.",
"Pro/THUDM/GLM-4.1V-9B-Thinking.description": "GLM-4.1V-9B-Thinking е отворен VLM модел, разработен от Zhipu AI и лабораторията KEG на университета Цинхуа, създаден за сложна мултимодална когниция. Базиран на GLM-4-9B-0414, той добавя верижно разсъждение (chain-of-thought) и обучение чрез подсилване (RL), което значително подобрява между-модалното разсъждение и стабилността.",
"Pro/THUDM/glm-4-9b-chat.description": "GLM-4-9B-Chat е отворен GLM-4 модел от Zhipu AI. Демонстрира високи резултати в семантика, математика, логическо мислене, програмиране и знания. Освен многозавойни разговори, поддържа уеб сърфиране, изпълнение на код, извикване на персонализирани инструменти и разсъждение върху дълги текстове. Поддържа 26 езика (включително китайски, английски, японски, корейски, немски). Представя се отлично в AlignBench-v2, MT-Bench, MMLU и C-Eval и поддържа до 128K контекст за академични и бизнес приложения.",
"Pro/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "DeepSeek-R1-Distill-Qwen-7B е дестилиран от Qwen2.5-Math-7B и фино настроен с 800K подбрани проби от DeepSeek-R1. Постига отлични резултати: 92.8% на MATH-500, 55.5% на AIME 2024 и рейтинг 1189 в CodeForces за 7B модел.",
"Pro/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "DeepSeek-R1-Distill-Qwen-7B е дистилиран от Qwen2.5-Math-7B и фино настроен върху 800K подбрани проби от DeepSeek-R1. Той показва силни резултати: 92.8% на MATH-500, 55.5% на AIME 2024 и рейтинг 1189 на CodeForces за модел с 7 милиарда параметри.",
"Pro/deepseek-ai/DeepSeek-R1.description": "DeepSeek-R1 е модел за разсъждение, базиран на обучение чрез подсилване (RL), който намалява повторенията и подобрява четимостта. Използва cold-start данни преди RL, за да засили разсъждението, съпоставя се с OpenAI-o1 при задачи по математика, код и логика и подобрява общите резултати чрез внимателно обучение.",
"Pro/deepseek-ai/DeepSeek-V3.1-Terminus.description": "DeepSeek-V3.1-Terminus е обновен модел от серията V3.1, позициониран като хибриден агентен LLM. Отстранява докладвани от потребители проблеми и подобрява стабилността, езиковата последователност и намалява смесването на китайски/английски и аномални символи. Интегрира режими с и без разсъждение с шаблони за чат за гъвкаво превключване. Подобрява и производителността на Code Agent и Search Agent за по-надеждно използване на инструменти и многoетапни задачи.",
"Pro/deepseek-ai/DeepSeek-V3.2.description": "DeepSeek-V3.2 е модел, който съчетава висока изчислителна ефективност с отлично разсъждение и производителност като агент. Подходът му се основава на три ключови технологични пробива: DeepSeek Sparse Attention (DSA), ефективен механизъм за внимание, който значително намалява изчислителната сложност, като същевременно поддържа производителността на модела и е специално оптимизиран за сценарии с дълъг контекст; мащабируема рамка за подсилващо обучение, чрез която производителността на модела може да съперничи на GPT-5, а версията с висока изчислителна мощност съответства на Gemini-3.0-Pro по способности за разсъждение; и мащабна тръбопроводна система за синтез на задачи за агенти, насочена към интегриране на способности за разсъждение в сценарии за използване на инструменти, като по този начин подобрява следването на инструкции и обобщаването в сложни интерактивни среди. Моделът постигна златен медал на Международната математическа олимпиада (IMO) и Международната олимпиада по информатика (IOI) през 2025 г.",
@@ -120,10 +127,10 @@
"Pro/moonshotai/Kimi-K2-Instruct-0905.description": "Kimi K2-Instruct-0905 е най-новият и най-мощен модел от серията Kimi K2. Това е MoE модел от най-висок клас с 1T общо и 32B активни параметъра. Основните му предимства включват по-силна агентна интелигентност при програмиране с значителни подобрения в бенчмаркове и реални задачи, както и подобрена естетика и използваемост на фронтенд кода.",
"Pro/moonshotai/Kimi-K2-Thinking.description": "Kimi K2 Thinking Turbo е ускорен вариант, оптимизиран за скорост на разсъждение и пропускателна способност, като запазва многoетапното разсъждение и използване на инструменти от K2 Thinking. Това е MoE модел с ~1T общи параметри, роден 256K контекст и стабилно мащабируемо извикване на инструменти за производствени сценарии с по-строги изисквания за латентност и едновременност.",
"Pro/moonshotai/Kimi-K2.5.description": "Kimi K2.5 е отворен мултимодален агентен модел, базиран на Kimi-K2-Base, обучен върху приблизително 1.5 трилиона смесени визуални и текстови токени. Моделът използва MoE архитектура с общо 1T параметри и 32B активни параметри, поддържа контекстен прозорец от 256K и безпроблемно интегрира визуално и езиково разбиране.",
"Pro/zai-org/glm-4.7.description": "GLM-4.7 е най-новият флагмански модел на Zhipu с общо 355 милиарда параметъра и 32 милиарда активни параметъра. Той е напълно обновен в областите на общ диалог, логическо мислене и агентни способности. GLM-4.7 подобрява Междинното мислене и въвежда Запазено мислене и Мислене на ниво обръщение.",
"Pro/zai-org/glm-4.7.description": "GLM-4.7 е новото поколение водещ модел на Zhipu с 355 милиарда общи параметри и 32 милиарда активни параметри, напълно обновен за общ диалог, разсъждения и агентни способности. GLM-4.7 подобрява преплетеното мислене и въвежда запазено мислене и мислене на ниво завой.",
"Pro/zai-org/glm-5.description": "GLM-5 е следващото поколение голям езиков модел на Zhipu, фокусиран върху сложното системно инженерство и задачи на агенти с дълга продължителност. Параметрите на модела са разширени до 744 милиарда (40 милиарда активни) и интегрират DeepSeek Sparse Attention.",
"QwQ-32B-Preview.description": "Qwen QwQ е експериментален изследователски модел, фокусиран върху подобряване на разсъждението.",
"Qwen/QVQ-72B-Preview.description": "QVQ-72B-Preview е изследователски модел от Qwen, насочен към визуално разсъждение, със силни страни в разбирането на сложни сцени и визуални математически задачи.",
"Qwen/QVQ-72B-Preview.description": "QVQ-72B-Preview е изследователски модел от Qwen, фокусиран върху визуално разсъждение, със силни страни в разбирането на сложни сцени и визуални математически задачи.",
"Qwen/QwQ-32B-Preview.description": "Qwen QwQ е експериментален изследователски модел, фокусиран върху подобрено AI разсъждение.",
"Qwen/QwQ-32B.description": "QwQ е модел за разсъждение от семейството Qwen. В сравнение със стандартните модели, настроени по инструкции, той добавя мисловни и логически способности, които значително подобряват представянето при трудни задачи. QwQ-32B е среден по размер модел, съпоставим с водещи модели за разсъждение като DeepSeek-R1 и o1-mini. Използва RoPE, SwiGLU, RMSNorm и QKV bias в вниманието, с 64 слоя и 40 Q глави (8 KV в GQA).",
"Qwen/Qwen-Image-Edit-2509.description": "Qwen-Image-Edit-2509 е най-новата версия за редактиране на изображения от екипа на Qwen. Базиран на 20B модела Qwen-Image, той разширява силното текстово рендиране към редактиране на изображения за прецизни текстови промени. Използва двуканална архитектура – входовете се подават към Qwen2.5-VL за семантичен контрол и към VAE енкодер за контрол на външния вид, което позволява редакции както на семантично, така и на визуално ниво. Поддържа локални редакции (добавяне/премахване/промяна) и по-високо ниво на семантични промени като създаване на IP и трансфер на стил, като същевременно запазва смисъла. Постига SOTA резултати в множество бенчмаркове.",
@@ -207,11 +214,11 @@
"Skylark2-pro-turbo-8k.description": "Модел от второ поколение Skylark. Skylark2-pro-turbo-8k предлага по-бърза инференция на по-ниска цена с контекстен прозорец от 8K.",
"THUDM/GLM-4-32B-0414.description": "GLM-4-32B-0414 е следващо поколение отворен GLM модел с 32 милиарда параметъра, сравним по производителност с OpenAI GPT и сериите DeepSeek V3/R1.",
"THUDM/GLM-4-9B-0414.description": "GLM-4-9B-0414 е 9-милиарден GLM модел, който наследява технологиите на GLM-4-32B, като същевременно предлага по-леко внедряване. Представя се добре в генериране на код, уеб дизайн, създаване на SVG и писане, базирано на търсене.",
"THUDM/GLM-4.1V-9B-Thinking.description": "GLM-4.1V-9B-Thinking е отворен VLM модел от Zhipu AI и лабораторията KEG на Цинхуа, създаден за сложна мултимодална когниция. Изграден върху GLM-4-9B-0414, добавя верижно разсъждение и подсилено обучение (RL), значително подобрявайки между-модалното разсъждение и стабилността.",
"THUDM/GLM-4.1V-9B-Thinking.description": "GLM-4.1V-9B-Thinking е модел с отворен код от Zhipu AI и лабораторията KEG на университета Цинхуа, създаден за сложна мултимодална когниция. Построен върху GLM-4-9B-0414, той добавя разсъждения чрез верига от мисли и RL за значително подобряване на кръстомодалното разсъждение и стабилност.",
"THUDM/GLM-Z1-32B-0414.description": "GLM-Z1-32B-0414 е модел за дълбоко разсъждение, изграден от GLM-4-32B-0414 с данни за студен старт и разширено подсилено обучение, допълнително обучен върху математика, код и логика. Значително подобрява способността за решаване на сложни задачи спрямо базовия модел.",
"THUDM/GLM-Z1-9B-0414.description": "GLM-Z1-9B-0414 е компактен GLM модел с 9 милиарда параметъра, който запазва силните страни на отворения код, като същевременно предлага впечатляващи възможности. Представя се отлично в математическо разсъждение и общи задачи, водещ в своя клас сред отворените модели.",
"THUDM/glm-4-9b-chat.description": "GLM-4-9B-Chat е отвореният GLM-4 модел от Zhipu AI. Представя се силно в семантика, математика, разсъждение, код и знания. Освен многозавойни чатове, поддържа уеб браузване, изпълнение на код, извикване на персонализирани инструменти и разсъждение върху дълги текстове. Поддържа 26 езика (включително китайски, английски, японски, корейски, немски). Представя се добре в AlignBench-v2, MT-Bench, MMLU и C-Eval и поддържа до 128K контекст за академична и бизнес употреба.",
"Tongyi-Zhiwen/QwenLong-L1-32B.description": "QwenLong-L1-32B е първият модел за разсъждение с дълъг контекст (LRM), обучен с подсилено обучение, оптимизиран за разсъждение върху дълги текстове. Неговото прогресивно разширяване на контекста чрез RL позволява стабилен преход от кратък към дълъг контекст. Надминава OpenAI-o3-mini и Qwen3-235B-A22B в седем бенчмарка за въпроси и отговори върху документи с дълъг контекст, съперничи на Claude-3.7-Sonnet-Thinking. Особено силен е в математика, логика и многозвенно разсъждение.",
"Tongyi-Zhiwen/QwenLong-L1-32B.description": "QwenLong-L1-32B е първият модел за разсъждение с дълъг контекст (LRM), обучен с RL, оптимизиран за разсъждение върху дълги текстове. Неговото прогресивно разширяване на контекста чрез RL позволява стабилен преход от кратък към дълъг контекст. Той надминава OpenAI-o3-mini и Qwen3-235B-A22B на седем бенчмарка за QA върху документи с дълъг контекст, съперничейки на Claude-3.7-Sonnet-Thinking. Особено силен е в математика, логика и многократни разсъждения.",
"Yi-34B-Chat.description": "Yi-1.5-34B запазва силните езикови способности на серията, като използва инкрементално обучение върху 500 милиарда висококачествени токена, за да подобри значително логиката в математиката и програмирането.",
"abab5.5-chat.description": "Създаден за продуктивни сценарии с обработка на сложни задачи и ефективно генериране на текст за професионална употреба.",
"abab5.5s-chat.description": "Проектиран за чат с китайски персонажи, осигуряващ висококачествен диалог на китайски език за различни приложения.",
@@ -303,15 +310,15 @@
"claude-3.5-sonnet.description": "Claude 3.5 Sonnet се отличава в програмиране, писане и сложни разсъждения.",
"claude-3.7-sonnet-thought.description": "Claude 3.7 Sonnet с разширено мислене за задачи, изискващи сложни разсъждения.",
"claude-3.7-sonnet.description": "Claude 3.7 Sonnet е надградена версия с разширен контекст и възможности.",
"claude-haiku-4-5-20251001.description": "Claude Haiku 4.5 е най-бързият и интелигентен Haiku модел на Anthropic, с мълниеносна скорост и разширено мислене.",
"claude-haiku-4-5-20251001.description": "Claude Haiku 4.5 е най-бързият и интелигентен модел Haiku на Anthropic, с мълниеносна скорост и разширено мислене.",
"claude-haiku-4.5.description": "Claude Haiku 4.5 е бърз и ефективен модел за различни задачи.",
"claude-opus-4-1-20250805-thinking.description": "Claude Opus 4.1 Thinking е усъвършенстван вариант, който може да разкрие процеса си на разсъждение.",
"claude-opus-4-1-20250805.description": "Claude Opus 4.1 е най-новият и най-способен модел на Anthropic за изключително сложни задачи, превъзхождащ в производителност, интелигентност, плавност и разбиране.",
"claude-opus-4-20250514.description": "Claude Opus 4 е най-мощният модел на Anthropic за изключително сложни задачи, превъзхождащ в производителност, интелигентност, плавност и разбиране.",
"claude-opus-4-1-20250805.description": "Claude Opus 4.1 е най-новият и най-способен модел на Anthropic за силно сложни задачи, отличаващ се с производителност, интелигентност, плавност и разбиране.",
"claude-opus-4-20250514.description": "Claude Opus 4 е най-мощният модел на Anthropic за силно сложни задачи, отличаващ се с производителност, интелигентност, плавност и разбиране.",
"claude-opus-4-5-20251101.description": "Claude Opus 4.5 е флагманският модел на Anthropic, комбиниращ изключителна интелигентност с мащабируема производителност, идеален за сложни задачи, изискващи най-висококачествени отговори и разсъждение.",
"claude-opus-4-6.description": "Claude Opus 4.6 е най-интелигентният модел на Anthropic за изграждане на агенти и програмиране.",
"claude-sonnet-4-20250514-thinking.description": "Claude Sonnet 4 Thinking може да генерира почти мигновени отговори или разширено стъпково мислене с видим процес.",
"claude-sonnet-4-20250514.description": "Claude Sonnet 4 е най-интелигентният модел на Anthropic досега, предлагащ почти мигновени отговори или разширено стъпка по стъпка мислене с прецизен контрол за API потребители.",
"claude-sonnet-4-20250514.description": "Claude Sonnet 4 е най-интелигентният модел на Anthropic досега, предлагащ почти мигновени отговори или разширено мислене стъпка по стъпка с фино управление за API потребители.",
"claude-sonnet-4-5-20250929.description": "Claude Sonnet 4.5 е най-интелигентният модел на Anthropic досега.",
"claude-sonnet-4-6.description": "Claude Sonnet 4.6 е най-добрата комбинация от скорост и интелигентност на Anthropic.",
"claude-sonnet-4.description": "Claude Sonnet 4 е най-новото поколение с подобрена производителност във всички задачи.",
@@ -370,7 +377,7 @@
"deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B.description": "Дестилираните модели DeepSeek-R1 използват RL и cold-start данни за подобряване на разсъждението и поставят нови бенчмарк стандарти за отворени модели с много задачи.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-14B.description": "Дестилираните модели DeepSeek-R1 използват RL и cold-start данни за подобряване на разсъждението и поставят нови бенчмарк стандарти за отворени модели с много задачи.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-32B.description": "DeepSeek-R1-Distill-Qwen-32B е дестилиран от Qwen2.5-32B и фино настроен върху 800K подбрани проби от DeepSeek-R1. Отличава се в математика, програмиране и разсъждение, постигайки силни резултати на AIME 2024, MATH-500 (94.3% точност) и GPQA Diamond.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "DeepSeek-R1-Distill-Qwen-7B е дестилиран от Qwen2.5-Math-7B и фино настроен върху 800K подбрани проби от DeepSeek-R1. Представя се силно с 92.8% на MATH-500, 55.5% на AIME 2024 и рейтинг 1189 в CodeForces за 7B модел.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "DeepSeek-R1-Distill-Qwen-7B е дистилиран от Qwen2.5-Math-7B и фино настроен върху 800K подбрани проби от DeepSeek-R1. Той показва силни резултати: 92.8% на MATH-500, 55.5% на AIME 2024 и рейтинг 1189 на CodeForces за модел с 7 милиарда параметри.",
"deepseek-ai/DeepSeek-R1.description": "DeepSeek-R1 подобрява разсъждението с RL и cold-start данни, поставяйки нови бенчмарк стандарти за отворени модели с много задачи и надминава OpenAI-o1-mini.",
"deepseek-ai/DeepSeek-V2.5.description": "DeepSeek-V2.5 надгражда DeepSeek-V2-Chat и DeepSeek-Coder-V2-Instruct, комбинирайки общи и кодови способности. Подобрява писането и следването на инструкции за по-добро съответствие с предпочитанията и показва значителни подобрения в AlpacaEval 2.0, ArenaHard, AlignBench и MT-Bench.",
"deepseek-ai/DeepSeek-V3.1-Terminus.description": "DeepSeek-V3.1-Terminus е обновен модел V3.1, позициониран като хибриден агентен LLM. Отстранява докладвани от потребители проблеми и подобрява стабилността, езиковата последователност и намалява смесените китайски/английски и аномални символи. Интегрира режими на мислене и немислене с шаблони за чат за гъвкаво превключване. Подобрява и производителността на Code Agent и Search Agent за по-надеждно използване на инструменти и многоетапни задачи.",
@@ -383,7 +390,7 @@
"deepseek-ai/deepseek-v3.1.description": "DeepSeek V3.1 е модел за разсъждение от ново поколение с по-силни способности за сложни разсъждения и верига от мисли за задълбочени аналитични задачи.",
"deepseek-ai/deepseek-v3.2.description": "DeepSeek V3.2 е модел за разсъждение от следващо поколение с по-силни способности за сложни разсъждения и верига на мисълта.",
"deepseek-ai/deepseek-vl2.description": "DeepSeek-VL2 е MoE модел за визия и език, базиран на DeepSeekMoE-27B със слаба активация, постигайки висока производителност с едва 4.5 милиарда активни параметъра. Отличава се в визуални въпроси и отговори, OCR, разбиране на документи/таблици/графики и визуално привързване.",
"deepseek-chat.description": "DeepSeek V3.2 балансира разсъжденията и дължината на изхода за ежедневни QA и агентски задачи. Публичните бенчмаркове достигат нива на GPT-5 и това е първият модел, който интегрира мислене в използването на инструменти, водещ до високи оценки в отворените източници за агенти.",
"deepseek-chat.description": "DeepSeek V3.2 балансира разсъжденията и дължината на изхода за ежедневни QA и задачи с агенти. Публичните бенчмаркове достигат нивата на GPT-5, и той е първият, който интегрира мислене в използването на инструменти, водещ в оценките на агенти с отворен код.",
"deepseek-coder-33B-instruct.description": "DeepSeek Coder 33B е езиков модел за програмиране, обучен върху 2 трилиона токени (87% код, 13% китайски/английски текст). Въвежда 16K контекстен прозорец и задачи за попълване в средата, осигурявайки допълване на код на ниво проект и попълване на фрагменти.",
"deepseek-coder-v2.description": "DeepSeek Coder V2 е отворен MoE модел за програмиране, който се представя на ниво GPT-4 Turbo.",
"deepseek-coder-v2:236b.description": "DeepSeek Coder V2 е отворен MoE модел за програмиране, който се представя на ниво GPT-4 Turbo.",
@@ -406,7 +413,7 @@
"deepseek-r1-fast-online.description": "Пълна бърза версия на DeepSeek R1 с търсене в реално време в уеб, комбинираща възможности от мащаб 671B и по-бърз отговор.",
"deepseek-r1-online.description": "Пълна версия на DeepSeek R1 с 671 милиарда параметъра и търсене в реално време в уеб, предлагаща по-силно разбиране и генериране.",
"deepseek-r1.description": "DeepSeek-R1 използва данни от студен старт преди подсиленото обучение и се представя наравно с OpenAI-o1 в математика, програмиране и разсъждение.",
"deepseek-reasoner.description": "DeepSeek V3.2 Thinking е модел за дълбоко разсъждение, който генерира верига от мисли преди изходите за по-висока точност, с топ резултати в конкуренцията и разсъждения, сравними с Gemini-3.0-Pro.",
"deepseek-reasoner.description": "DeepSeek V3.2 Thinking е модел за дълбоко разсъждение, който генерира верига от мисли преди изходите за по-висока точност, с водещи резултати в състезания и разсъждения, сравними с Gemini-3.0-Pro.",
"deepseek-v2.description": "DeepSeek V2 е ефективен MoE модел за икономична обработка.",
"deepseek-v2:236b.description": "DeepSeek V2 236B е модел на DeepSeek, фокусиран върху програмиране, с висока производителност при генериране на код.",
"deepseek-v3-0324.description": "DeepSeek-V3-0324 е MoE модел с 671 милиарда параметъра, с изключителни способности в програмиране, технически задачи, разбиране на контекст и обработка на дълги текстове.",
@@ -417,7 +424,7 @@
"deepseek-v3.2-exp.description": "deepseek-v3.2-exp въвежда разредено внимание за подобряване на ефективността при обучение и извеждане върху дълги текстове, на по-ниска цена от deepseek-v3.1.",
"deepseek-v3.2-speciale.description": "При силно сложни задачи, моделът Speciale значително превъзхожда стандартната версия, но консумира значително повече токени и води до по-високи разходи. В момента DeepSeek-V3.2-Speciale е предназначен само за изследователска употреба, не поддържа използване на инструменти и не е специално оптимизиран за ежедневни разговори или задачи за писане.",
"deepseek-v3.2-think.description": "DeepSeek V3.2 Think е пълен модел за дълбоко мислене с по-силно дълговерижно разсъждение.",
"deepseek-v3.2.description": "DeepSeek-V3.2 е първият хибриден модел за логическо мислене от DeepSeek, който интегрира мисленето в използването на инструменти. Използва ефективна архитектура за намаляване на изчислителните ресурси, мащабно обучение с подсилване за повишаване на способностите и синтетични задачи в голям мащаб за по-добра обобщаемост. Комбинацията от тези три елемента постига производителност, сравнима с GPT-5-High, със значително по-кратки изходни текстове, което намалява изчислителното натоварване и времето за изчакване на потребителя.",
"deepseek-v3.2.description": "DeepSeek-V3.2 е най-новият модел за програмиране на DeepSeek със силни способности за разсъждение.",
"deepseek-v3.description": "DeepSeek-V3 е мощен MoE модел с общо 671 милиарда параметъра и 37 милиарда активни на токен.",
"deepseek-vl2-small.description": "DeepSeek VL2 Small е лек мултимодален вариант за среди с ограничени ресурси и висока едновременност.",
"deepseek-vl2.description": "DeepSeek VL2 е мултимодален модел за разбиране на изображения и текст и прецизни визуални въпроси и отговори.",
@@ -506,8 +513,8 @@
"ernie-x1-turbo-32k.description": "ERNIE X1 Turbo 32K е бърз мислещ модел с 32K контекст за сложни разсъждения и многозавойни разговори.",
"ernie-x1.1-preview.description": "ERNIE X1.1 Preview е предварителен модел за мислене, предназначен за оценка и тестване.",
"ernie-x1.1.description": "ERNIE X1.1 е мисловен модел за предварителен преглед за оценка и тестване.",
"fal-ai/bytedance/seedream/v4.5.description": "Seedream 4.5, създаден от екипа на ByteDance Seed, поддържа редактиране и композиция на множество изображения. Характеризира се с подобрена консистентност на обектите, прецизно следване на инструкции, разбиране на пространствена логика, естетическо изразяване, оформление на плакати и дизайн на лога с високопрецизно текстово-изображение рендиране.",
"fal-ai/bytedance/seedream/v4.description": "Seedream 4.0, създаден от ByteDance Seed, поддържа текстови и визуални входове за високо контролируемо, висококачествено генериране на изображения от подсказки.",
"fal-ai/bytedance/seedream/v4.5.description": "Seedream 4.5, създаден от екипа Seed на ByteDance, поддържа редактиране и композиция на множество изображения. Характеризира се с подобрена консистентност на обектите, прецизно следване на инструкции, разбиране на пространствена логика, естетично изразяване, оформление на плакати и дизайн на лого с високопрецизно текстово-изображение рендиране.",
"fal-ai/bytedance/seedream/v4.description": "Seedream 4.0, създаден от ByteDance Seed, поддържа текстови и визуални входове за силно контролируемо, висококачествено генериране на изображения от подсказки.",
"fal-ai/flux-kontext/dev.description": "FLUX.1 модел, фокусиран върху редактиране на изображения, поддържащ вход от текст и изображения.",
"fal-ai/flux-pro/kontext.description": "FLUX.1 Kontext [pro] приема текст и референтни изображения като вход, позволявайки целенасочени локални редакции и сложни глобални трансформации на сцени.",
"fal-ai/flux/krea.description": "Flux Krea [dev] е модел за генериране на изображения с естетично предпочитание към по-реалистични и естествени изображения.",
@@ -515,8 +522,8 @@
"fal-ai/hunyuan-image/v3.description": "Мощен роден мултимодален модел за генериране на изображения.",
"fal-ai/imagen4/preview.description": "Модел за висококачествено генериране на изображения от Google.",
"fal-ai/nano-banana.description": "Nano Banana е най-новият, най-бърз и най-ефективен роден мултимодален модел на Google, позволяващ генериране и редактиране на изображения чрез разговор.",
"fal-ai/qwen-image-edit.description": "Професионален модел за редактиране на изображения от екипа на Qwen, поддържащ семантични и визуални редакции, прецизно редактиране на текст на китайски/английски, трансфер на стил, ротация и други.",
"fal-ai/qwen-image.description": "Мощен модел за генериране на изображения от екипа на Qwen със силно рендиране на китайски текст и разнообразни визуални стилове.",
"fal-ai/qwen-image-edit.description": "Професионален модел за редактиране на изображения от екипа Qwen, поддържащ семантични и визуални редакции, прецизно редактиране на текст на китайски/английски, трансфер на стил, ротация и други.",
"fal-ai/qwen-image.description": "Мощен модел за генериране на изображения от екипа Qwen със силно рендиране на китайски текст и разнообразни визуални стилове.",
"flux-1-schnell.description": "Модел за преобразуване на текст в изображение с 12 милиарда параметъра от Black Forest Labs, използващ латентна дифузионна дестилация за генериране на висококачествени изображения в 1–4 стъпки. Съперничи на затворени алтернативи и е пуснат под лиценз Apache-2.0 за лична, изследователска и търговска употреба.",
"flux-dev.description": "FLUX.1 [dev] е дестилиран модел с отворени тегла за нетърговска употреба. Запазва почти професионално качество на изображенията и следване на инструкции, като същевременно работи по-ефективно и използва ресурсите по-добре от стандартни модели със същия размер.",
"flux-kontext-max.description": "Съвременно генериране и редактиране на изображения с контекст, комбиниращо текст и изображения за прецизни и последователни резултати.",
@@ -560,10 +567,10 @@
"gemini-2.5-pro.description": "Gemini 2.5 Pro е най-усъвършенстваният модел за разсъждение на Google, способен да разсъждава върху код, математика и STEM проблеми и да анализира големи набори от данни, кодови бази и документи с дълъг контекст.",
"gemini-3-flash-preview.description": "Gemini 3 Flash е най-интелигентният модел, създаден за скорост, съчетаващ авангардна интелигентност с отлично търсене и обоснованост.",
"gemini-3-pro-image-preview.description": "Gemini 3 Pro Image (Nano Banana Pro) е модел за генериране на изображения на Google, който също поддържа мултимодален диалог.",
"gemini-3-pro-image-preview:image.description": "Gemini 3 Pro Image (Nano Banana Pro) е моделът на Google за генериране на изображения и също така поддържа мултимодален чат.",
"gemini-3-pro-image-preview:image.description": "Gemini 3 Pro Image (Nano Banana Pro) е модел на Google за генериране на изображения, който също поддържа мултимодален чат.",
"gemini-3-pro-preview.description": "Gemini 3 Pro е най-мощният агентен и „vibe-coding“ модел на Google, който предлага по-богати визуализации и по-дълбоко взаимодействие, базирано на съвременно логическо мислене.",
"gemini-3.1-flash-image-preview.description": "Gemini 3.1 Flash Image (Nano Banana 2) е най-бързият модел на Google за генериране на изображения с поддръжка на мислене, разговорно генериране и редактиране на изображения.",
"gemini-3.1-flash-image-preview:image.description": "Gemini 3.1 Flash Image (Nano Banana 2) предоставя Pro-качество на изображения с Flash скорост и поддръжка на мултимодален чат.",
"gemini-3.1-flash-image-preview:image.description": "Gemini 3.1 Flash Image (Nano Banana 2) предлага качество на изображения от ниво Pro с Flash скорост и поддръжка на мултимодален чат.",
"gemini-3.1-flash-lite-preview.description": "Gemini 3.1 Flash-Lite Preview е най-икономичният мултимодален модел на Google, оптимизиран за задачи с голям обем, превод и обработка на данни.",
"gemini-3.1-pro-preview.description": "Gemini 3.1 Pro Preview подобрява Gemini 3 Pro с усъвършенствани способности за разсъждение и добавя поддръжка за средно ниво на мислене.",
"gemini-flash-latest.description": "Най-новата версия на Gemini Flash",
@@ -798,7 +805,7 @@
"kimi-k2-thinking-turbo.description": "Високоскоростен вариант на K2 с дълбоко мислене, 256k контекст, силно дълбоко разсъждение и скорост на изход от 60–100 токена/сек.",
"kimi-k2-thinking.description": "kimi-k2-thinking е мисловен модел на Moonshot AI с общи агентни и разсъждателни способности. Отличава се с дълбоко разсъждение и може да решава трудни задачи чрез многостъпкова употреба на инструменти.",
"kimi-k2-turbo-preview.description": "kimi-k2 е MoE базов модел с мощни способности за програмиране и агентни задачи (1T общи параметри, 32B активни), надминаващ други водещи отворени модели в области като разсъждение, програмиране, математика и агентни бенчмаркове.",
"kimi-k2.5.description": "Kimi K2.5 е най-способният модел на Kimi, предоставящ водещи резултати с отворен код в агентни задачи, програмиране и визуално разбиране. Поддържа мултимодални входове и режими с и без мислене.",
"kimi-k2.5.description": "Kimi K2.5 е най-универсалният модел на Kimi досега, с родна мултимодална архитектура, която поддържа както визуални, така и текстови входове, режими 'мислене' и 'немислене', както и задачи за разговори и агенти.",
"kimi-k2.description": "Kimi-K2 е MoE базов модел от Moonshot AI с мощни способности за програмиране и агентни задачи, с общо 1T параметри и 32B активни. В бенчмаркове за общо разсъждение, програмиране, математика и агентни задачи надминава други водещи отворени модели.",
"kimi-k2:1t.description": "Kimi K2 е голям MoE LLM от Moonshot AI с 1T общи параметри и 32B активни на всяко преминаване. Оптимизиран е за агентни способности, включително напреднало използване на инструменти, разсъждение и синтез на код.",
"kuaishou/kat-coder-pro-v1.description": "KAT-Coder-Pro-V1 (ограничено безплатен) се фокусира върху разбиране на код и автоматизация за ефективни кодиращи агенти.",
@@ -960,7 +967,7 @@
"moonshot-v1-32k.description": "Moonshot V1 32K поддържа 32 768 токена за средно дълъг контекст, идеален за дълги документи и сложни диалози в създаване на съдържание, отчети и чат системи.",
"moonshot-v1-8k-vision-preview.description": "Моделите Kimi vision (включително moonshot-v1-8k-vision-preview/moonshot-v1-32k-vision-preview/moonshot-v1-128k-vision-preview) разбират съдържание на изображения като текст, цветове и форми на обекти.",
"moonshot-v1-8k.description": "Moonshot V1 8K е оптимизиран за генериране на кратки текстове с висока ефективност, обработвайки 8 192 токена за кратки чатове, бележки и бързо съдържание.",
"moonshotai/Kimi-Dev-72B.description": "Kimi-Dev-72B е отворен кодов езиков модел, оптимизиран с мащабно подсилващо обучение за създаване на стабилни, готови за продукция корекции. Постига 60.4% в SWE-bench Verified, поставяйки нов рекорд сред отворените модели за автоматизирани задачи като отстраняване на грешки и преглед на код.",
"moonshotai/Kimi-Dev-72B.description": "Kimi-Dev-72B е модел за програмиране с отворен код, оптимизиран с мащабно RL за създаване на надеждни, готови за производство корекции. Той постига 60.4% на SWE-bench Verified, поставяйки нов рекорд за модели с отворен код в автоматизирани задачи като поправка на грешки и преглед на код.",
"moonshotai/Kimi-K2-Instruct-0905.description": "Kimi K2-Instruct-0905 е най-новият и най-мощен модел от серията Kimi K2. Това е MoE модел от най-висок клас с 1T общо и 32B активни параметъра. Основни характеристики включват по-силна агентна интелигентност при програмиране, значителни подобрения в бенчмаркове и реални задачи, както и подобрена естетика и използваемост на фронтенд кода.",
"moonshotai/Kimi-K2-Thinking.description": "Kimi K2 Thinking е най-новият и най-мощен модел за мислене с отворен код. Той значително разширява дълбочината на многократното разсъждение и поддържа стабилно използване на инструменти в 200–300 последователни извиквания, поставяйки нови рекорди на Humanity's Last Exam (HLE), BrowseComp и други бенчмаркове. Превъзхожда в кодиране, математика, логика и сценарии с агенти. Изграден на архитектура MoE с ~1 трилион общи параметри, поддържа 256K контекстен прозорец и извикване на инструменти.",
"moonshotai/kimi-k2-0711.description": "Kimi K2 0711 е instruct вариант от серията Kimi, подходящ за висококачествен код и използване на инструменти.",
@@ -1163,6 +1170,7 @@
"qwen3-coder-next.description": "Следващо поколение Qwen кодер, оптимизиран за сложна многокодова генерация, дебъгване и високопроизводителни работни потоци на агенти. Създаден за силна интеграция на инструменти и подобрена производителност на разсъждения.",
"qwen3-coder-plus.description": "Модел за програмиране Qwen. Най-новата серия Qwen3-Coder е базирана на Qwen3 и предлага силни способности за програмиране чрез агенти, използване на инструменти и взаимодействие със среди за автономно програмиране, с отлично представяне при код и стабилни общи възможности.",
"qwen3-coder:480b.description": "Високопроизводителен модел на Alibaba с дълъг контекст за задачи с агенти и програмиране.",
"qwen3-max-2026-01-23.description": "Qwen3 Max: Най-добре представящият се модел Qwen за сложни, многократни задачи по програмиране с поддръжка на мислене.",
"qwen3-max-preview.description": "Най-добре представящият се модел Qwen за сложни, многоетапни задачи. Прегледната версия поддържа разсъждение.",
"qwen3-max.description": "Моделите Qwen3 Max предлагат значителни подобрения спрямо серията 2.5 в общите способности, разбиране на китайски/английски, следване на сложни инструкции, субективни отворени задачи, многоезичност и използване на инструменти, с по-малко халюцинации. Най-новият qwen3-max подобрява програмирането чрез агенти и използването на инструменти спрямо qwen3-max-preview. Тази версия достига водещи резултати в индустрията и е насочена към по-сложни нужди на агентите.",
"qwen3-next-80b-a3b-instruct.description": "Следващо поколение отворен модел Qwen3 без мисловни способности. В сравнение с предишната версия (Qwen3-235B-A22B-Instruct-2507), предлага по-добро разбиране на китайски, по-силна логическа аргументация и подобрено генериране на текст.",
@@ -1192,8 +1200,8 @@
"qwq.description": "QwQ е модел за аргументация от семейството на Qwen. В сравнение със стандартните модели, обучени с инструкции, предлага мисловни и логически способности, които значително подобряват ефективността при трудни задачи. QwQ-32B е среден по размер модел, който се конкурира с водещи модели като DeepSeek-R1 и o1-mini.",
"qwq_32b.description": "Среден по размер модел за аргументация от семейството на Qwen. В сравнение със стандартните модели, обучени с инструкции, мисловните и логическите способности на QwQ значително подобряват ефективността при трудни задачи.",
"r1-1776.description": "R1-1776 е дообучен вариант на DeepSeek R1, създаден да предоставя неконфронтирана, обективна и фактическа информация.",
"seedance-1-5-pro-251215.description": "Seedance 1.5 Pro от ByteDance поддържа текст-към-видео, изображение-към-видео (първи кадър, първи+последен кадър) и генериране на аудио, синхронизирано с визуализации.",
"seedream-5-0-260128.description": "ByteDance-Seedream-5.0-lite от BytePlus предлага генериране, обогатено с уеб търсене за реална информация, подобрена интерпретация на сложни подсказки и подобрена консистентност на референциите за професионално визуално създаване.",
"seedance-1-5-pro-251215.description": "Seedance 1.5 Pro от ByteDance поддържа текст към видео, изображение към видео (първа рамка, първа+последна рамка) и генериране на аудио, синхронизирано с визуализации.",
"seedream-5-0-260128.description": "ByteDance-Seedream-5.0-lite от BytePlus предлага генериране, обогатено с уеб търсене за реална информация, подобрена интерпретация на сложни подсказки и подобрена консистентност на препратките за професионално визуално създаване.",
"solar-mini-ja.description": "Solar Mini (Ja) разширява Solar Mini с фокус върху японски език, като запазва ефективността и силната производителност на английски и корейски.",
"solar-mini.description": "Solar Mini е компактен LLM, който превъзхожда GPT-3.5, с мощни многоезични възможности, поддържащ английски и корейски, и предлага ефективно решение с малък отпечатък.",
"solar-pro.description": "Solar Pro е интелигентен LLM от Upstage, фокусиран върху следване на инструкции на един GPU, с IFEval резултати над 80. Понастоящем поддържа английски; пълното издание е планирано за ноември 2024 с разширена езикова поддръжка и по-дълъг контекст.",
@@ -1229,7 +1237,7 @@
"step-3.5-flash.description": "Флагманският модел за езиково разсъждение на Stepfun. Този модел има първокласни способности за разсъждение и бързи и надеждни изпълнителни възможности. Може да разлага и планира сложни задачи, бързо и надеждно да извиква инструменти за изпълнение на задачи и да бъде компетентен в различни сложни задачи като логическо разсъждение, математика, софтуерно инженерство и задълбочени изследвания.",
"step-3.description": "Този модел притежава силно визуално възприятие и сложна логика, точно обработва междудомейново знание, анализ между математика и визия и широк спектър от ежедневни визуални задачи.",
"step-r1-v-mini.description": "Модел за логическо разсъждение със силно визуално разбиране, който може да обработва изображения и текст, след което да генерира текст след дълбоко разсъждение. Отличава се във визуално разсъждение и предоставя водещи резултати в математика, програмиране и текстово разсъждение, с контекстен прозорец от 100K.",
"stepfun-ai/step3.description": "Step3 е авангарден мултимодален модел за разсъждение от StepFun, изграден върху MoE архитектура с общо 321B и 38B активни параметъра. Дизайнът от край до край минимизира разходите за декодиране, като същевременно осигурява водещо разсъждение между визия и език. С MFA и AFD дизайн, остава ефективен както на флагмански, така и на нискобюджетни ускорители. Предобучен с над 20T текстови токени и 4T токени от изображения и текст на множество езици. Постига водеща производителност сред отворените модели в математика, код и мултимодални бенчмаркове.",
"stepfun-ai/step3.description": "Step3 е авангарден модел за мултимодално разсъждение от StepFun, построен върху архитектура MoE с 321 милиарда общи и 38 милиарда активни параметри. Неговият дизайн от край до край минимизира разходите за декодиране, като същевременно осигурява водещо разсъждение за визия и език. С дизайна MFA и AFD, той остава ефективен както на водещи, така и на нискобюджетни ускорители. Предварителното обучение използва над 20 трилиона текстови токени и 4 трилиона токени за изображения-текстове на много езици. Той достига водещи резултати сред модели с отворен код в математика, код и мултимодални бенчмаркове.",
"taichu4_vl_2b_nothinking.description": "Версията без мислене на модела Taichu4.0-VL 2B се отличава с по-ниска употреба на памет, лек дизайн, бърза скорост на отговор и силни способности за мултимодално разбиране.",
"taichu4_vl_32b.description": "Версията с мислене на модела Taichu4.0-VL 32B е подходяща за сложни задачи за мултимодално разбиране и разсъждение, демонстрирайки изключителна производителност в мултимодално математическо разсъждение, мултимодални способности на агенти и общо разбиране на изображения и визуализации.",
"taichu4_vl_32b_nothinking.description": "Версията без мислене на модела Taichu4.0-VL 32B е предназначена за сложни сценарии за разбиране на изображения и текст и визуални въпроси и отговори, превъзхождайки в описания на изображения, визуални въпроси и отговори, разбиране на видео и задачи за визуална локализация.",
@@ -1316,7 +1324,7 @@
"zai-org/GLM-4.5-Air.description": "GLM-4.5-Air е базов модел за агентни приложения с архитектура Mixture-of-Experts. Оптимизиран е за използване на инструменти, уеб браузване, софтуерно инженерство и фронтенд програмиране, и се интегрира с кодови агенти като Claude Code и Roo Code. Използва хибридно разсъждение за справяне както със сложни, така и с ежедневни задачи.",
"zai-org/GLM-4.5V.description": "GLM-4.5V е най-новият визуален езиков модел (VLM) на Zhipu AI, изграден върху флагманския текстов модел GLM-4.5-Air (106B общо, 12B активни) с MoE архитектура за висока производителност при по-ниска цена. Следва пътя на GLM-4.1V-Thinking и добавя 3D-RoPE за подобрено пространствено разсъждение в 3D. Оптимизиран чрез предварително обучение, SFT и RL, обработва изображения, видео и дълги документи и е сред водещите отворени модели в 41 публични мултимодални бенчмарка. Режимът Thinking позволява на потребителите да балансират между скорост и дълбочина.",
"zai-org/GLM-4.6.description": "В сравнение с GLM-4.5, GLM-4.6 разширява контекста от 128K до 200K за по-сложни агентни задачи. Постига по-високи резултати в кодови бенчмаркове и показва по-добра реална производителност в приложения като Claude Code, Cline, Roo Code и Kilo Code, включително по-добро генериране на фронтенд страници. Разсъждението е подобрено и се поддържа използване на инструменти по време на разсъждение, което засилва цялостните възможности. По-добре се интегрира в агентни рамки, подобрява инструментите/търсещите агенти и има по-предпочитан от хора стил на писане и естественост в ролевите сценарии.",
"zai-org/GLM-4.6V.description": "GLM-4.6V постига SOTA точност за визуално разбиране за своя мащаб на параметрите и е първият, който нативно интегрира способности за извикване на функции в архитектурата на модела за визия, преодолявайки разликата между визуално възприятие и изпълними действия и предоставяйки унифицирана техническа основа за мултимодални агенти в реални бизнес сценарии. Визуалният контекстен прозорец е разширен до 128k, поддържащ обработка на дълги видео потоци и анализ на изображения с висока резолюция.",
"zai-org/GLM-4.6V.description": "GLM-4.6V постига водеща точност във визуалното разбиране за своя мащаб на параметрите и е първият, който нативно интегрира възможности за извикване на функции в архитектурата на визуалния модел, преодолявайки разликата между \"визуално възприятие\" и \"изпълними действия\" и предоставяйки унифицирана техническа основа за мултимодални агенти в реални бизнес сценарии. Визуалният контекстен прозорец е разширен до 128 хиляди, поддържайки обработка на дълги видео потоци и анализ на изображения с висока резолюция.",
"zai/glm-4.5-air.description": "GLM-4.5 и GLM-4.5-Air са най-новите ни флагмани за агентни приложения, и двата използват MoE. GLM-4.5 има 355B общо и 32B активни параметри на стъпка; GLM-4.5-Air е по-лек с 106B общо и 12B активни.",
"zai/glm-4.5.description": "Серията GLM-4.5 е проектирана за агенти. Флагманският GLM-4.5 комбинира разсъждение, програмиране и агентни умения с 355B общи параметри (32B активни) и предлага два режима на работа като хибридна система за разсъждение.",
"zai/glm-4.5v.description": "GLM-4.5V надгражда GLM-4.5-Air, наследявайки доказани техники от GLM-4.1V-Thinking и мащабира с мощна MoE архитектура с 106 милиарда параметъра.",
+1 -1
View File
@@ -1,6 +1,7 @@
{
"arguments.moreParams": "{{count}} параметъра общо",
"arguments.title": "Аргументи",
"builtins.lobe-activator.apiName.activateTools": "Активиране на инструменти",
"builtins.lobe-agent-builder.apiName.getAvailableModels": "Извличане на налични модели",
"builtins.lobe-agent-builder.apiName.getAvailableTools": "Извличане на налични умения",
"builtins.lobe-agent-builder.apiName.getConfig": "Извличане на конфигурация",
@@ -209,7 +210,6 @@
"builtins.lobe-skills.apiName.runCommand": "Изпълни команда",
"builtins.lobe-skills.apiName.searchSkill": "Търсене на умения",
"builtins.lobe-skills.title": "Умения",
"builtins.lobe-tools.apiName.activateTools": "Активиране на инструменти",
"builtins.lobe-topic-reference.apiName.getTopicContext": "Вземи контекста на темата",
"builtins.lobe-topic-reference.title": "Препратка към тема",
"builtins.lobe-user-memory.apiName.addContextMemory": "Добавяне на контекстна памет",
+6 -1
View File
@@ -8,6 +8,7 @@
"azure.description": "Azure предлага усъвършенствани AI модели, включително сериите GPT-3.5 и GPT-4, за разнообразни типове данни и сложни задачи с фокус върху безопасен, надежден и устойчив AI.",
"azureai.description": "Azure предоставя усъвършенствани AI модели, включително сериите GPT-3.5 и GPT-4, за разнообразни типове данни и сложни задачи с акцент върху безопасен, надежден и устойчив AI.",
"baichuan.description": "Baichuan AI се фокусира върху базови модели с висока ефективност при китайски знания, обработка на дълъг контекст и креативно генериране. Моделите му (Baichuan 4, Baichuan 3 Turbo, Baichuan 3 Turbo 128k) са оптимизирани за различни сценарии и предлагат висока стойност.",
"bailiancodingplan.description": "Aliyun Bailian Coding Plan е специализирана AI услуга за програмиране, предоставяща достъп до модели, оптимизирани за програмиране, като Qwen, GLM, Kimi и MiniMax чрез специален крайна точка.",
"bedrock.description": "Amazon Bedrock предоставя на предприятията усъвършенствани езикови и визуални модели, включително Anthropic Claude и Meta Llama 3.1, обхващащи от леки до високопроизводителни опции за текст, чат и изображения.",
"bfl.description": "Водеща изследователска лаборатория в областта на frontier AI, изграждаща визуалната инфраструктура на бъдещето.",
"cerebras.description": "Cerebras е платформа за инференция, изградена върху системата CS-3, фокусирана върху ултраниска латентност и висок капацитет за LLM услуги в реално време като генериране на код и агентни задачи.",
@@ -21,6 +22,7 @@
"giteeai.description": "Gitee AI Serverless API предоставят готови за използване услуги за LLM инференция за разработчици.",
"github.description": "С GitHub Models разработчиците могат да работят като AI инженери, използвайки водещи в индустрията модели.",
"githubcopilot.description": "Достъпвайте моделите Claude, GPT и Gemini чрез вашия абонамент за GitHub Copilot.",
"glmcodingplan.description": "GLM Coding Plan предоставя достъп до модели на Zhipu AI, включително GLM-5 и GLM-4.7, за задачи, свързани с програмиране, чрез абонамент с фиксирана такса.",
"google.description": "Семейството Gemini на Google е най-усъвършенстваният му универсален AI, създаден от Google DeepMind за мултимодална употреба с текст, код, изображения, аудио и видео. Работи както в центрове за данни, така и на мобилни устройства с висока ефективност и обхват.",
"groq.description": "Инференционният енджин LPU на Groq осигурява изключителна производителност с висока скорост и ефективност, поставяйки нов стандарт за нисколатентна облачна LLM инференция.",
"higress.description": "Higress е облачно-нативен API gateway, създаден в Alibaba за справяне с проблемите при презареждане на Tengine и липсите в балансирането на натоварването при gRPC/Dubbo.",
@@ -29,10 +31,12 @@
"infiniai.description": "Предоставя на разработчиците на приложения високоефективни, лесни за използване и сигурни LLM услуги за целия работен процес — от разработка на модел до внедряване в продукция.",
"internlm.description": "Open-source организация, фокусирана върху изследвания и инструменти за големи модели, предоставяща ефективна и лесна за използване платформа за достъп до водещи модели и алгоритми.",
"jina.description": "Основана през 2020 г., Jina AI е водеща компания в областта на търсещия AI. Технологичният ѝ стек включва векторни модели, преоценители и малки езикови модели за създаване на надеждни генеративни и мултимодални търсещи приложения.",
"kimicodingplan.description": "Kimi Code от Moonshot AI предоставя достъп до модели Kimi, включително K2.5, за задачи, свързани с програмиране.",
"lmstudio.description": "LM Studio е десктоп приложение за разработка и експериментиране с LLM на вашия компютър.",
"lobehub.description": "LobeHub Cloud използва официални API-та за достъп до AI модели и измерва използването с Кредити, свързани с токените на модела.",
"lobehub.description": "LobeHub Cloud използва официални API за достъп до AI модели и измерва използването чрез кредити, свързани с токените на модела.",
"longcat.description": "LongCat е серия от големи модели за генеративен AI, независимо разработени от Meituan. Той е създаден да подобри вътрешната продуктивност на предприятието и да позволи иновативни приложения чрез ефективна изчислителна архитектура и силни мултимодални възможности.",
"minimax.description": "Основана през 2021 г., MiniMax създава универсален AI с мултимодални базови модели, включително текстови модели с трилиони параметри, речеви и визуални модели, както и приложения като Hailuo AI.",
"minimaxcodingplan.description": "MiniMax Token Plan предоставя достъп до модели MiniMax, включително M2.7, за задачи, свързани с програмиране, чрез абонамент с фиксирана такса.",
"mistral.description": "Mistral предлага усъвършенствани универсални, специализирани и изследователски модели за сложни разсъждения, многоезични задачи и генериране на код, с извикване на функции за персонализирани интеграции.",
"modelscope.description": "ModelScope е платформа на Alibaba Cloud за модели като услуга, предлагаща широка гама от AI модели и услуги за инференция.",
"moonshot.description": "Moonshot, от Moonshot AI (Beijing Moonshot Technology), предлага множество NLP модели за създаване на съдържание, изследвания, препоръки и медицински анализи, с поддръжка на дълъг контекст и сложни генерации.",
@@ -65,6 +69,7 @@
"vertexai.description": "Семейството Gemini на Google е най-усъвършенстваният му универсален AI, създаден от Google DeepMind за мултимодална употреба с текст, код, изображения, аудио и видео. Работи както в центрове за данни, така и на мобилни устройства, подобрявайки ефективността и гъвкавостта на внедряване.",
"vllm.description": "vLLM е бърза и лесна за използване библиотека за инференция и обслужване на LLM.",
"volcengine.description": "Платформата за модели на ByteDance предлага сигурен, богат на функции и икономичен достъп до модели, както и цялостни инструменти за данни, фино настройване, инференция и оценка.",
"volcenginecodingplan.description": "Volcengine Coding Plan от ByteDance предоставя достъп до множество модели за програмиране, включително Doubao-Seed-Code, GLM-4.7, DeepSeek-V3.2 и Kimi-K2.5, чрез абонамент с фиксирана такса.",
"wenxin.description": "Платформа за предприятия за базови модели и разработка на AI-приложения, предлагаща цялостни инструменти за работни потоци с генеративен AI.",
"xai.description": "xAI създава AI за ускоряване на научните открития с мисията да задълбочи разбирането на човечеството за Вселената.",
"xiaomimimo.description": "Xiaomi MiMo предоставя услуга за разговорен модел с API, съвместим с OpenAI. Моделът mimo-v2-flash поддържа задълбочено разсъждение, поточно извеждане, извикване на функции, контекстен прозорец от 256K и максимален изход от 128K.",
+65
View File
@@ -193,6 +193,70 @@
"analytics.title": "Анализ",
"checking": "Проверка...",
"checkingPermissions": "Проверка на разрешенията...",
"creds.actions.delete": "Изтрий",
"creds.actions.deleteConfirm.cancel": "Отказ",
"creds.actions.deleteConfirm.content": "Този идентификатор ще бъде изтрит завинаги. Това действие не може да бъде отменено.",
"creds.actions.deleteConfirm.ok": "Изтрий",
"creds.actions.deleteConfirm.title": "Изтриване на идентификатор?",
"creds.actions.edit": "Редактирай",
"creds.actions.view": "Преглед",
"creds.create": "Нов идентификатор",
"creds.createModal.fillForm": "Попълнете детайлите",
"creds.createModal.selectType": "Изберете тип",
"creds.createModal.title": "Създаване на идентификатор",
"creds.edit.title": "Редактиране на идентификатор",
"creds.empty": "Все още няма конфигурирани идентификатори",
"creds.file.authRequired": "Моля, влезте в Market първо",
"creds.file.uploadFailed": "Качването на файла не бе успешно",
"creds.file.uploadSuccess": "Файлът беше качен успешно",
"creds.file.uploading": "Качване...",
"creds.form.addPair": "Добавяне на ключ-стойност двойка",
"creds.form.back": "Назад",
"creds.form.cancel": "Отказ",
"creds.form.connectionRequired": "Моля, изберете OAuth връзка",
"creds.form.description": "Описание",
"creds.form.descriptionPlaceholder": "По избор описание за този идентификатор",
"creds.form.file": "Файл с идентификатор",
"creds.form.fileRequired": "Моля, качете файл",
"creds.form.key": "Идентификатор",
"creds.form.keyPattern": "Идентификаторът може да съдържа само букви, цифри, долни черти и тирета",
"creds.form.keyRequired": "Идентификаторът е задължителен",
"creds.form.name": "Име за показване",
"creds.form.nameRequired": "Името за показване е задължително",
"creds.form.save": "Запази",
"creds.form.selectConnection": "Изберете OAuth връзка",
"creds.form.selectConnectionPlaceholder": "Изберете свързан акаунт",
"creds.form.selectedFile": "Избран файл",
"creds.form.submit": "Създай",
"creds.form.uploadDesc": "Поддържа JSON, PEM и други формати на файлове с идентификатори",
"creds.form.uploadHint": "Кликнете или плъзнете файл за качване",
"creds.form.valuePlaceholder": "Въведете стойност",
"creds.form.values": "Ключ-стойност двойки",
"creds.oauth.noConnections": "Няма налични OAuth връзки. Моля, свържете акаунт първо.",
"creds.signIn": "Влезте в Market",
"creds.signInRequired": "Моля, влезте в Market, за да управлявате вашите идентификатори",
"creds.table.actions": "Действия",
"creds.table.key": "Идентификатор",
"creds.table.lastUsed": "Последно използван",
"creds.table.name": "Име",
"creds.table.neverUsed": "Никога",
"creds.table.preview": "Преглед",
"creds.table.type": "Тип",
"creds.typeDesc.file": "Качете файлове с идентификатори като акаунти за услуги или сертификати",
"creds.typeDesc.kv-env": "Съхранявайте API ключове и токени като променливи на средата",
"creds.typeDesc.kv-header": "Съхранявайте стойности за удостоверяване като HTTP заглавки",
"creds.typeDesc.oauth": "Свържете се със съществуваща OAuth връзка",
"creds.types.all": "Всички",
"creds.types.file": "Файл",
"creds.types.kv-env": "Среда",
"creds.types.kv-header": "Заглавка",
"creds.types.oauth": "OAuth",
"creds.view.error": "Неуспешно зареждане на идентификатора",
"creds.view.noValues": "Няма стойности",
"creds.view.oauthNote": "OAuth идентификаторите се управляват от свързаната услуга.",
"creds.view.title": "Преглед на идентификатор: {{name}}",
"creds.view.values": "Стойности на идентификатора",
"creds.view.warning": "Тези стойности са чувствителни. Не ги споделяйте с други.",
"danger.clear.action": "Изчисти сега",
"danger.clear.confirm": "Да се изтрият ли всички чат данни? Това действие не може да бъде отменено.",
"danger.clear.desc": "Изтриване на всички данни, включително агенти, файлове, съобщения и умения. Вашият акаунт НЯМА да бъде изтрит.",
@@ -731,6 +795,7 @@
"tab.appearance": "Външен вид",
"tab.chatAppearance": "Външен вид на чата",
"tab.common": "Външен вид",
"tab.creds": "Идентификатори",
"tab.experiment": "Експеримент",
"tab.hotkey": "Клавишни комбинации",
"tab.image": "Услуга за генериране на изображения",
+5
View File
@@ -199,6 +199,8 @@
"plans.btn.paymentDesc": "Поддържа кредитна карта / Alipay / WeChat Pay",
"plans.btn.paymentDescForZarinpal": "Поддържа кредитна карта",
"plans.btn.soon": "Очаквайте скоро",
"plans.cancelDowngrade": "Отмяна на планираното понижение",
"plans.cancelDowngradeSuccess": "Планираното понижение е отменено",
"plans.changePlan": "Избери план",
"plans.cloud.history": "Неограничена история на разговорите",
"plans.cloud.sync": "Синхронизация в облака по целия свят",
@@ -215,6 +217,7 @@
"plans.current": "Текущ план",
"plans.downgradePlan": "Целеви понижен план",
"plans.downgradeTip": "Вече си сменил абонамента. Не можеш да извършваш други действия, докато смяната не приключи",
"plans.downgradeWillCancel": "Това действие ще отмени планираното понижение на плана ви",
"plans.embeddingStorage.embeddings": "записа",
"plans.embeddingStorage.title": "Векторно съхранение",
"plans.embeddingStorage.tooltip": "Една страница документ (1000-1500 знака) генерира приблизително 1 векторен запис. (Оценено с OpenAI Embeddings, може да варира според модела)",
@@ -253,6 +256,7 @@
"plans.payonce.ok": "Потвърди избора",
"plans.payonce.popconfirm": "След еднократно плащане трябва да изчакаш изтичането на абонамента, за да смениш план или цикъл на плащане. Потвърди избора си.",
"plans.payonce.tooltip": "При еднократно плащане трябва да изчакаш изтичането на абонамента, за да смениш план или цикъл на плащане",
"plans.pendingDowngrade": "Очакващо понижение",
"plans.plan.enterprise.contactSales": "Свържи се с търговски представител",
"plans.plan.enterprise.title": "Бизнес",
"plans.plan.free.desc": "За нови потребители",
@@ -366,6 +370,7 @@
"summary.title": "Обобщение на таксуването",
"summary.usageThisMonth": "Вижте използването си за този месец.",
"summary.viewBillingHistory": "Виж история на плащанията",
"switchDowngradeTarget": "Смяна на целта за понижение",
"switchPlan": "Смени план",
"switchToMonthly.desc": "След смяната, месечното таксуване ще влезе в сила след изтичане на текущия годишен план.",
"switchToMonthly.title": "Превключване към месечно таксуване",
+37 -1
View File
@@ -1,5 +1,6 @@
{
"channel.appSecret": "App-Geheimnis",
"channel.appSecretHint": "Das App-Geheimnis Ihrer Bot-Anwendung. Es wird verschlüsselt und sicher gespeichert.",
"channel.appSecretPlaceholder": "Fügen Sie hier Ihr App-Geheimnis ein",
"channel.applicationId": "Anwendungs-ID / Bot-Benutzername",
"channel.applicationIdHint": "Eindeutige Kennung für Ihre Bot-Anwendung.",
@@ -9,14 +10,31 @@
"channel.botTokenHowToGet": "Wie erhalten?",
"channel.botTokenPlaceholderExisting": "Token ist aus Sicherheitsgründen verborgen",
"channel.botTokenPlaceholderNew": "Fügen Sie hier Ihr Bot-Token ein",
"channel.charLimit": "Zeichenlimit",
"channel.charLimitHint": "Maximale Anzahl von Zeichen pro Nachricht",
"channel.connectFailed": "Bot-Verbindung fehlgeschlagen",
"channel.connectSuccess": "Bot erfolgreich verbunden",
"channel.connecting": "Verbinden...",
"channel.connectionConfig": "Verbindungskonfiguration",
"channel.copied": "In die Zwischenablage kopiert",
"channel.copy": "Kopieren",
"channel.credentials": "Anmeldedaten",
"channel.debounceMs": "Nachrichten-Merge-Fenster (ms)",
"channel.debounceMsHint": "Wie lange auf zusätzliche Nachrichten warten, bevor sie an den Agenten weitergeleitet werden (ms)",
"channel.deleteConfirm": "Sind Sie sicher, dass Sie diesen Kanal entfernen möchten?",
"channel.deleteConfirmDesc": "Diese Aktion entfernt diesen Nachrichtenkanal und seine Konfiguration dauerhaft. Dies kann nicht rückgängig gemacht werden.",
"channel.devWebhookProxyUrl": "HTTPS-Tunnel-URL",
"channel.devWebhookProxyUrlHint": "Optional. HTTPS-Tunnel-URL zum Weiterleiten von Webhook-Anfragen an den lokalen Entwicklungsserver.",
"channel.disabled": "Deaktiviert",
"channel.discord.description": "Verbinden Sie diesen Assistenten mit einem Discord-Server für Kanal-Chat und Direktnachrichten.",
"channel.dm": "Direktnachrichten",
"channel.dmEnabled": "DMs aktivieren",
"channel.dmEnabledHint": "Erlauben Sie dem Bot, Direktnachrichten zu empfangen und darauf zu antworten",
"channel.dmPolicy": "DM-Richtlinie",
"channel.dmPolicyAllowlist": "Whitelist",
"channel.dmPolicyDisabled": "Deaktiviert",
"channel.dmPolicyHint": "Steuern Sie, wer Direktnachrichten an den Bot senden kann",
"channel.dmPolicyOpen": "Offen",
"channel.documentation": "Dokumentation",
"channel.enabled": "Aktiviert",
"channel.encryptKey": "Verschlüsselungsschlüssel",
@@ -26,6 +44,7 @@
"channel.endpointUrlHint": "Bitte kopieren Sie diese URL und fügen Sie sie in das Feld <bold>{{fieldName}}</bold> im {{name}} Entwicklerportal ein.",
"channel.feishu.description": "Verbinden Sie diesen Assistenten mit Feishu für private und Gruppenchats.",
"channel.lark.description": "Verbinden Sie diesen Assistenten mit Lark für private und Gruppenchats.",
"channel.openPlatform": "Offene Plattform",
"channel.platforms": "Plattformen",
"channel.publicKey": "Öffentlicher Schlüssel",
"channel.publicKeyHint": "Optional. Wird verwendet, um Interaktionsanfragen von Discord zu überprüfen.",
@@ -42,6 +61,16 @@
"channel.secretToken": "Webhook-Geheimtoken",
"channel.secretTokenHint": "Optional. Wird verwendet, um Webhook-Anfragen von Telegram zu überprüfen.",
"channel.secretTokenPlaceholder": "Optionales Geheimnis zur Webhook-Verifizierung",
"channel.settings": "Erweiterte Einstellungen",
"channel.settingsResetConfirm": "Sind Sie sicher, dass Sie die erweiterten Einstellungen auf die Standardeinstellungen zurücksetzen möchten?",
"channel.settingsResetDefault": "Auf Standard zurücksetzen",
"channel.setupGuide": "Einrichtungsanleitung",
"channel.showUsageStats": "Nutzungsstatistiken anzeigen",
"channel.showUsageStatsHint": "Zeigen Sie Token-Nutzung, Kosten und Dauerstatistiken in Bot-Antworten an",
"channel.signingSecret": "Signatur-Geheimnis",
"channel.signingSecretHint": "Wird verwendet, um Webhook-Anfragen zu verifizieren.",
"channel.slack.appIdHint": "Ihre Slack-App-ID aus dem Slack-API-Dashboard (beginnt mit A).",
"channel.slack.description": "Verbinden Sie diesen Assistenten mit Slack für Kanalgespräche und Direktnachrichten.",
"channel.telegram.description": "Verbinden Sie diesen Assistenten mit Telegram für private und Gruppenchats.",
"channel.testConnection": "Verbindung testen",
"channel.testFailed": "Verbindungstest fehlgeschlagen",
@@ -50,5 +79,12 @@
"channel.validationError": "Bitte füllen Sie Anwendungs-ID und Token aus",
"channel.verificationToken": "Verifizierungstoken",
"channel.verificationTokenHint": "Optional. Wird verwendet, um die Quelle von Webhook-Ereignissen zu überprüfen.",
"channel.verificationTokenPlaceholder": "Fügen Sie hier Ihr Verifizierungstoken ein"
"channel.verificationTokenPlaceholder": "Fügen Sie hier Ihr Verifizierungstoken ein",
"channel.wechat.description": "Verbinden Sie diesen Assistenten mit WeChat über iLink Bot für private und Gruppenchats.",
"channel.wechatQrExpired": "QR-Code abgelaufen. Bitte aktualisieren Sie, um einen neuen zu erhalten.",
"channel.wechatQrRefresh": "QR-Code aktualisieren",
"channel.wechatQrScaned": "QR-Code gescannt. Bitte bestätigen Sie die Anmeldung in WeChat.",
"channel.wechatQrWait": "Öffnen Sie WeChat und scannen Sie den QR-Code, um eine Verbindung herzustellen.",
"channel.wechatScanTitle": "WeChat-Bot verbinden",
"channel.wechatScanToConnect": "QR-Code scannen, um eine Verbindung herzustellen"
}
+3 -1
View File
@@ -397,7 +397,6 @@
"sync.status.unconnected": "Verbindung fehlgeschlagen",
"sync.title": "Synchronisationsstatus",
"sync.unconnected.tip": "Verbindung zum Signalisierungsserver fehlgeschlagen, Peer-to-Peer-Kommunikationskanal kann nicht aufgebaut werden. Bitte überprüfen Sie Ihre Netzwerkverbindung und versuchen Sie es erneut.",
"tab.aiImage": "Kunstwerk",
"tab.audio": "Audio",
"tab.chat": "Chat",
"tab.community": "Community",
@@ -405,6 +404,7 @@
"tab.eval": "Bewertungslabor",
"tab.files": "Dateien",
"tab.home": "Startseite",
"tab.image": "Bild",
"tab.knowledgeBase": "Bibliothek",
"tab.marketplace": "Marktplatz",
"tab.me": "Ich",
@@ -432,6 +432,7 @@
"userPanel.billing": "Abrechnungsverwaltung",
"userPanel.cloud": "{{name}} starten",
"userPanel.community": "Community",
"userPanel.credits": "Kreditverwaltung",
"userPanel.data": "Datenspeicherung",
"userPanel.defaultNickname": "Community-Benutzer",
"userPanel.discord": "Community-Support",
@@ -443,6 +444,7 @@
"userPanel.plans": "Abonnementpläne",
"userPanel.profile": "Konto",
"userPanel.setting": "Einstellungen",
"userPanel.upgradePlan": "Plan upgraden",
"userPanel.usages": "Nutzungsstatistiken",
"version": "Version"
}
+5
View File
@@ -83,6 +83,11 @@
"preference.empty": "Keine Präferenz-Erinnerungen verfügbar",
"preference.source": "Quelle",
"preference.suggestions": "Mögliche Handlungen des Agenten",
"purge.action": "Alle löschen",
"purge.confirm": "Sind Sie sicher, dass Sie alle Erinnerungen löschen möchten? Dies wird alle Erinnerungseinträge dauerhaft entfernen und kann nicht rückgängig gemacht werden.",
"purge.error": "Das Löschen der Erinnerungen ist fehlgeschlagen. Bitte versuchen Sie es erneut.",
"purge.success": "Alle Erinnerungen wurden gelöscht.",
"purge.title": "Alle Erinnerungen löschen",
"tab.activities": "Aktivitäten",
"tab.contexts": "Kontexte",
"tab.experiences": "Erfahrungen",
+2
View File
@@ -231,6 +231,8 @@
"providerModels.item.modelConfig.extendParams.options.imageResolution.hint": "Für Gemini 3 Bildgenerierungsmodelle; steuert die Auflösung der generierten Bilder.",
"providerModels.item.modelConfig.extendParams.options.imageResolution2.hint": "Für Gemini 3.1 Flash Image-Modelle; steuert die Auflösung der generierten Bilder (unterstützt 512px).",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken.hint": "Für Claude, Qwen3 und ähnliche Modelle; steuert das Token-Budget für logisches Denken.",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken32k.hint": "Für GLM-5 und GLM-4.7; steuert das Token-Budget für das logische Denken (max. 32k).",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken80k.hint": "Für die Qwen3-Serie; steuert das Token-Budget für das logische Denken (max. 80k).",
"providerModels.item.modelConfig.extendParams.options.reasoningEffort.hint": "Für OpenAI und andere Modelle mit Denkfähigkeit; steuert den Denkaufwand.",
"providerModels.item.modelConfig.extendParams.options.textVerbosity.hint": "Für die GPT-5+-Serie; steuert die Ausführlichkeit der Ausgabe.",
"providerModels.item.modelConfig.extendParams.options.thinking.hint": "Für einige Doubao-Modelle; erlaubt dem Modell zu entscheiden, ob es tiefgründig denken soll.",
+39 -31
View File
@@ -53,7 +53,14 @@
"FLUX.1-Kontext-dev.description": "FLUX.1-Kontext-dev ist ein multimodales Modell zur Bildgenerierung und -bearbeitung von Black Forest Labs, basierend auf einer Rectified Flow Transformer-Architektur mit 12 Milliarden Parametern. Es konzentriert sich auf die Erzeugung, Rekonstruktion, Verbesserung oder Bearbeitung von Bildern unter gegebenen Kontextbedingungen. Es kombiniert die kontrollierbare Generierung von Diffusionsmodellen mit der Kontextmodellierung von Transformern und unterstützt hochwertige Ergebnisse für Aufgaben wie Inpainting, Outpainting und visuelle Szenenrekonstruktion.",
"FLUX.1-Kontext-pro.description": "FLUX.1 Kontext [pro]",
"FLUX.1-dev.description": "FLUX.1-dev ist ein Open-Source-multimodales Sprachmodell (MLLM) von Black Forest Labs, optimiert für Bild-Text-Aufgaben. Es kombiniert Bild-/Textverständnis und -generierung. Basierend auf fortschrittlichen LLMs (z.B. Mistral-7B) nutzt es einen sorgfältig entwickelten Vision-Encoder und mehrstufiges Instruction-Tuning für multimodale Koordination und komplexes logisches Denken.",
"GLM-4.5-Air.description": "GLM-4.5-Air: Leichtgewichtige Version für schnelle Antworten.",
"GLM-4.5.description": "GLM-4.5: Hochleistungsmodell für logisches Denken, Programmierung und Agentenaufgaben.",
"GLM-4.6.description": "GLM-4.6: Modell der vorherigen Generation.",
"GLM-4.7.description": "GLM-4.7 ist Zhipus neuestes Flaggschiffmodell, optimiert für agentenbasierte Codierungsszenarien mit verbesserten Programmierfähigkeiten, langfristiger Aufgabenplanung und Werkzeugzusammenarbeit.",
"GLM-5-Turbo.description": "GLM-5-Turbo: Optimierte Version von GLM-5 mit schnellerer Inferenz für Programmieraufgaben.",
"GLM-5.description": "GLM-5 ist Zhipus Flaggschiffmodell der nächsten Generation, speziell entwickelt für agentenbasierte Ingenieursaufgaben. Es bietet zuverlässige Produktivität in komplexen Systemingenieurprojekten und langfristigen agentenbasierten Aufgaben. In den Bereichen Programmierung und Agentenfähigkeiten erreicht GLM-5 Spitzenleistungen unter Open-Source-Modellen.",
"Gryphe/MythoMax-L2-13b.description": "MythoMax-L2 (13B) ist ein innovatives Modell für vielfältige Anwendungsbereiche und komplexe Aufgaben.",
"HY-Image-V3.0.description": "Leistungsstarke Funktionen zur Extraktion von Originalbildern und zur Detailerhaltung, die eine reichere visuelle Textur liefern und hochpräzise, gut komponierte, produktionsreife Bilder erzeugen.",
"HelloMeme.description": "HelloMeme ist ein KI-Tool zur Erstellung von Memes, GIFs oder Kurzvideos aus bereitgestellten Bildern oder Bewegungen. Es erfordert keine Zeichen- oder Programmierkenntnisse ein Referenzbild genügt, um unterhaltsame, ansprechende und stilistisch konsistente Inhalte zu erzeugen.",
"HiDream-E1-Full.description": "HiDream-E1-Full ist ein Open-Source-Multimodell-Bildbearbeitungsmodell von HiDream.ai, basierend auf einer fortschrittlichen Diffusion Transformer-Architektur und starker Sprachverständnisfähigkeit (integriertes LLaMA 3.1-8B-Instruct). Es unterstützt natürliche Sprachsteuerung für Bildgenerierung, Stiltransfer, lokale Bearbeitungen und Übermalungen mit hervorragendem Bild-Text-Verständnis und Ausführung.",
"HiDream-I1-Full.description": "HiDream-I1 ist ein neues Open-Source-Basis-Bildgenerierungsmodell von HiDream. Mit 17 Milliarden Parametern (Flux hat 12 Milliarden) liefert es branchenführende Bildqualität in Sekundenschnelle.",
@@ -84,14 +91,14 @@
"MiniMax-M2.1-highspeed.description": "Leistungsstarke mehrsprachige Programmierfähigkeiten mit schnellerer und effizienterer Inferenz.",
"MiniMax-M2.1.description": "MiniMax-M2.1 ist das Flaggschiff unter den Open-Source-Großmodellen von MiniMax und konzentriert sich auf die Lösung komplexer Aufgaben aus der realen Welt. Seine zentralen Stärken liegen in der mehrsprachigen Programmierfähigkeit und der Fähigkeit, als Agent komplexe Aufgaben zu bewältigen.",
"MiniMax-M2.5-Lightning.description": "M2.5 Lightning: Gleiche Leistung, schneller und agiler (ca. 100 tps).",
"MiniMax-M2.5-highspeed.description": "Gleiche Leistung wie M2.5 mit deutlich schnellerer Inferenz.",
"MiniMax-M2.5-highspeed.description": "MiniMax M2.5 Highspeed: Gleiche Leistung wie M2.5 mit schnellerer Inferenz.",
"MiniMax-M2.5.description": "MiniMax-M2.5 ist ein Flaggschiff-Open-Source-Großmodell von MiniMax, das sich auf die Lösung komplexer realer Aufgaben konzentriert. Seine Kernstärken sind mehrsprachige Programmierfähigkeiten und die Fähigkeit, komplexe Aufgaben als Agent zu lösen.",
"MiniMax-M2.7-highspeed.description": "Gleiche Leistung wie M2.7 mit deutlich schnellerer Inferenz (~100 tps).",
"MiniMax-M2.7.description": "Erstes selbst-evolvierendes Modell mit erstklassiger Codierungs- und agentischer Leistung (~60 tps).",
"MiniMax-M2.description": "Speziell für effizientes Programmieren und Agenten-Workflows entwickelt",
"MiniMax-M2.7-highspeed.description": "MiniMax M2.7 Highspeed: Gleiche Leistung wie M2.7 mit deutlich schnellerer Inferenz.",
"MiniMax-M2.7.description": "MiniMax M2.7: Beginn der Reise zur rekursiven Selbstverbesserung, erstklassige reale Ingenieursfähigkeiten.",
"MiniMax-M2.description": "MiniMax M2: Modell der vorherigen Generation.",
"MiniMax-Text-01.description": "MiniMax-01 führt großskalige lineare Aufmerksamkeit über klassische Transformer hinaus ein. Mit 456B Parametern und 45,9B aktiv pro Durchlauf erreicht es Spitzenleistung und unterstützt bis zu 4M Token Kontext (32× GPT-4o, 20× Claude-3.5-Sonnet).",
"MiniMaxAI/MiniMax-M1-80k.description": "MiniMax-M1 ist ein Open-Weights-Modell für großskalige hybride Aufmerksamkeits- und Schlussfolgerungsaufgaben mit insgesamt 456 Milliarden Parametern und etwa 45,9 Milliarden aktiven Parametern pro Token. Es unterstützt nativ einen Kontext von 1 Million Tokens und nutzt Flash Attention, um die FLOPs bei der Generierung von 100.000 Tokens im Vergleich zu DeepSeek R1 um 75 % zu reduzieren. Durch die MoE-Architektur, CISPO und hybrides RL-Training erzielt es führende Leistungen bei Aufgaben mit langen Eingaben und realer Softwareentwicklung.",
"MiniMaxAI/MiniMax-M2.description": "MiniMax-M2 definiert Effizienz für Agenten neu. Es handelt sich um ein kompaktes, schnelles und kosteneffizientes MoE-Modell mit insgesamt 230 Milliarden und 10 Milliarden aktiven Parametern, das für erstklassige Programmier- und Agentenaufgaben entwickelt wurde und gleichzeitig eine starke allgemeine Intelligenz beibehält. Trotz nur 10 Milliarden aktiver Parameter konkurriert es mit deutlich größeren Modellen und eignet sich ideal für Anwendungen mit hoher Effizienz.",
"MiniMaxAI/MiniMax-M1-80k.description": "MiniMax-M1 ist ein großskaliges Hybrid-Attention-Reasoning-Modell mit offenen Gewichten, 456 Milliarden Gesamtparametern und ~45,9 Milliarden aktiven Parametern pro Token. Es unterstützt nativ 1 Million Kontext und verwendet Flash Attention, um FLOPs bei der Generierung von 100.000 Tokens im Vergleich zu DeepSeek R1 um 75 % zu reduzieren. Mit einer MoE-Architektur sowie CISPO und Hybrid-Attention-RL-Training erreicht es führende Leistungen bei langem Input-Reasoning und realen Software-Engineering-Aufgaben.",
"MiniMaxAI/MiniMax-M2.description": "MiniMax-M2 definiert die Effizienz von Agenten neu. Es ist ein kompaktes, schnelles und kosteneffizientes MoE-Modell mit 230 Milliarden Gesamt- und 10 Milliarden aktiven Parametern, entwickelt für erstklassige Programmier- und Agentenaufgaben bei gleichzeitig starker allgemeiner Intelligenz. Mit nur 10 Milliarden aktiven Parametern konkurriert es mit deutlich größeren Modellen und ist ideal für hocheffiziente Anwendungen.",
"Moonshot-Kimi-K2-Instruct.description": "1 Billion Gesamtparameter mit 32 Milliarden aktiven. Unter den nicht-denkenden Modellen gehört es zur Spitzenklasse in den Bereichen aktuelles Wissen, Mathematik und Programmierung und ist besonders stark bei allgemeinen Agentenaufgaben. Optimiert für Agenten-Workloads kann es nicht nur Fragen beantworten, sondern auch Handlungen ausführen. Ideal für improvisierte, allgemeine Chats und Agentenerlebnisse als reflexartiges Modell ohne langes Nachdenken.",
"NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO.description": "Nous Hermes 2 - Mixtral 8x7B-DPO (46,7B) ist ein hochpräzises Anweisungsmodell für komplexe Berechnungen.",
"OmniConsistency.description": "OmniConsistency verbessert die Stil-Konsistenz und Generalisierung bei Bild-zu-Bild-Aufgaben durch den Einsatz großskaliger Diffusion Transformers (DiTs) und gepaarter stilisierter Daten, wodurch Stilverluste vermieden werden.",
@@ -105,14 +112,14 @@
"Phi-3.5-mini-instruct.description": "Eine aktualisierte Version des Phi-3-mini-Modells.",
"Phi-3.5-vision-instrust.description": "Eine aktualisierte Version des Phi-3-vision-Modells.",
"Pro/MiniMaxAI/MiniMax-M2.1.description": "MiniMax-M2.1 ist ein Open-Source-Sprachmodell der nächsten Generation, das für agentenbasierte Fähigkeiten optimiert wurde. Es überzeugt in den Bereichen Programmierung, Werkzeugnutzung, Befolgen von Anweisungen und langfristige Planung. Das Modell unterstützt mehrsprachige Softwareentwicklung und die Ausführung komplexer, mehrstufiger Arbeitsabläufe. Es erreichte 74,0 Punkte im SWE-bench Verified und übertrifft Claude Sonnet 4.5 in mehrsprachigen Szenarien.",
"Pro/MiniMaxAI/MiniMax-M2.5.description": "MiniMax-M2.5 ist das neueste große Sprachmodell von MiniMax, das durch groß angelegtes Reinforcement Learning in Hunderttausenden komplexer realer Umgebungen trainiert wurde. Mit einer MoE-Architektur und 229 Milliarden Parametern erreicht es branchenführende Leistungen in Aufgaben wie Programmierung, Agenten-Tool-Aufrufen, Suche und Büroszenarien.",
"Pro/MiniMaxAI/MiniMax-M2.5.description": "MiniMax-M2.5 ist das neueste große Sprachmodell von MiniMax, trainiert durch großskaliges Reinforcement Learning in Hunderttausenden komplexer, realer Umgebungen. Mit einer MoE-Architektur und 229 Milliarden Parametern erreicht es branchenführende Leistungen bei Aufgaben wie Programmierung, Agenten-Tool-Nutzung, Suche und Büroszenarien.",
"Pro/Qwen/Qwen2-7B-Instruct.description": "Qwen2-7B-Instruct ist ein 7B-Instruktionsmodell der Qwen2-Serie. Es verwendet eine Transformer-Architektur mit SwiGLU, Attention-QKV-Bias und Grouped-Query-Attention und verarbeitet große Eingaben. Es zeigt starke Leistungen in Sprachverständnis, Textgenerierung, Mehrsprachigkeit, Programmierung, Mathematik und logischem Denken, übertrifft die meisten Open-Source-Modelle und konkurriert mit proprietären Modellen. Es übertrifft Qwen1.5-7B-Chat in mehreren Benchmarks.",
"Pro/Qwen/Qwen2.5-7B-Instruct.description": "Qwen2.5-7B-Instruct ist Teil der neuesten LLM-Serie von Alibaba Cloud. Das 7B-Modell bietet deutliche Verbesserungen in den Bereichen Programmierung und Mathematik, unterstützt über 29 Sprachen und verbessert das Befolgen von Anweisungen, das Verständnis strukturierter Daten und strukturierte Ausgaben (insbesondere JSON).",
"Pro/Qwen/Qwen2.5-Coder-7B-Instruct.description": "Qwen2.5-Coder-7B-Instruct ist das neueste codefokussierte LLM von Alibaba Cloud. Basierend auf Qwen2.5 und trainiert mit 5,5 Billionen Tokens verbessert es die Codegenerierung, das logische Denken und die Fehlerbehebung erheblich, während es mathematische und allgemeine Stärken beibehält eine solide Grundlage für Coding-Agenten.",
"Pro/Qwen/Qwen2.5-VL-7B-Instruct.description": "Qwen2.5-VL ist ein neues Vision-Language-Modell der Qwen-Serie mit starker visueller Verständnisfähigkeit. Es analysiert Text, Diagramme und Layouts in Bildern, versteht lange Videos und Ereignisse, unterstützt logisches Denken und Werkzeugnutzung, Objektverankerung in mehreren Formaten und strukturierte Ausgaben. Es verbessert die dynamische Auflösung und das Frame-Rate-Training für Videoverständnis und steigert die Effizienz des Vision-Encoders.",
"Pro/THUDM/GLM-4.1V-9B-Thinking.description": "GLM-4.1V-9B-Thinking ist ein Open-Source-VLM von Zhipu AI und dem Tsinghua KEG Lab, entwickelt für komplexe multimodale Kognition. Basierend auf GLM-4-9B-0414 erweitert es das Chain-of-Thought-Denken und RL, um das multimodale Schlussfolgern und die Stabilität deutlich zu verbessern.",
"Pro/THUDM/glm-4-9b-chat.description": "GLM-4-9B-Chat ist das Open-Source-Modell GLM-4 von Zhipu AI. Es zeigt starke Leistungen in Semantik, Mathematik, logischem Denken, Programmierung und Wissen. Neben mehrstufigem Chat unterstützt es Web-Browsing, Codeausführung, benutzerdefinierte Tool-Aufrufe und langes Textverständnis. Es unterstützt 26 Sprachen (darunter Chinesisch, Englisch, Japanisch, Koreanisch, Deutsch) und bietet bis zu 128K Kontext für akademische und geschäftliche Anwendungen.",
"Pro/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "DeepSeek-R1-Distill-Qwen-7B ist eine Destillation von Qwen2.5-Math-7B und wurde mit 800.000 kuratierten DeepSeek-R1-Beispielen feinabgestimmt. Es erzielt starke Leistungen mit 92,8 % auf MATH-500, 55,5 % auf AIME 2024 und einem CodeForces-Rating von 1189 für ein 7B-Modell.",
"Pro/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "DeepSeek-R1-Distill-Qwen-7B wurde aus Qwen2.5-Math-7B destilliert und auf 800.000 kuratierten DeepSeek-R1-Proben feinabgestimmt. Es erzielt starke Leistungen mit 92,8 % bei MATH-500, 55,5 % bei AIME 2024 und einer CodeForces-Bewertung von 1189 für ein 7B-Modell.",
"Pro/deepseek-ai/DeepSeek-R1.description": "DeepSeek-R1 ist ein durch RL optimiertes Schlussfolgerungsmodell, das Wiederholungen reduziert und die Lesbarkeit verbessert. Es verwendet Cold-Start-Daten vor dem RL, um das logische Denken weiter zu verbessern, erreicht vergleichbare Leistungen wie OpenAI-o1 bei Mathematik-, Code- und Denkaufgaben und verbessert die Gesamtergebnisse durch sorgfältiges Training.",
"Pro/deepseek-ai/DeepSeek-V3.1-Terminus.description": "DeepSeek-V3.1-Terminus ist eine aktualisierte Version des V3.1-Modells, das als hybrides Agenten-LLM positioniert ist. Es behebt von Nutzern gemeldete Probleme, verbessert die Stabilität und Sprachkonsistenz und reduziert gemischte chinesisch/englische Ausgaben und fehlerhafte Zeichen. Es integriert Denk- und Nicht-Denk-Modi mit Chat-Vorlagen für flexibles Umschalten. Außerdem verbessert es die Leistung von Code- und Suchagenten für zuverlässigere Werkzeugnutzung und mehrstufige Aufgaben.",
"Pro/deepseek-ai/DeepSeek-V3.2.description": "DeepSeek-V3.2 ist ein Modell, das hohe Rechenleistungseffizienz mit exzellenter Argumentation und Agentenleistung kombiniert. Sein Ansatz basiert auf drei technologischen Durchbrüchen: DeepSeek Sparse Attention (DSA), einem effizienten Aufmerksamkeitsmechanismus, der die Rechenkomplexität erheblich reduziert und gleichzeitig die Modellleistung beibehält, speziell optimiert für Langkontext-Szenarien; einem skalierbaren Reinforcement-Learning-Framework, durch das die Modellleistung mit GPT-5 konkurrieren kann, wobei die Hochleistungsvariante mit Gemini-3.0-Pro in Argumentationsfähigkeiten vergleichbar ist; und einer groß angelegten Agenten-Aufgabensynthese-Pipeline, die darauf abzielt, Argumentationsfähigkeiten in Werkzeugszenarien zu integrieren, um die Befolgung von Anweisungen und die Generalisierung in komplexen interaktiven Umgebungen zu verbessern. Das Modell erreichte Goldmedaillenleistungen bei der Internationalen Mathematik-Olympiade (IMO) und der Internationalen Informatik-Olympiade (IOI) 2025.",
@@ -120,10 +127,10 @@
"Pro/moonshotai/Kimi-K2-Instruct-0905.description": "Kimi K2-Instruct-0905 ist das neueste und leistungsstärkste Modell der Kimi K2-Reihe. Es handelt sich um ein MoE-Spitzenmodell mit insgesamt 1 Billion und 32 Milliarden aktiven Parametern. Zu den Hauptmerkmalen zählen eine verbesserte agentenbasierte Programmierintelligenz mit deutlichen Leistungssteigerungen bei Benchmarks und realen Agentenaufgaben sowie eine optimierte Ästhetik und Benutzerfreundlichkeit im Frontend-Coding.",
"Pro/moonshotai/Kimi-K2-Thinking.description": "Kimi K2 Thinking Turbo ist die Turbo-Variante, die für hohe Geschwindigkeit und Durchsatz beim logischen Denken optimiert wurde, während die Fähigkeit zu mehrstufigem Denken und Werkzeugnutzung von K2 Thinking erhalten bleibt. Es handelt sich um ein MoE-Modell mit etwa 1 Billion Parametern, nativem 256K-Kontext und stabiler großskaliger Tool-Nutzung für Produktionsszenarien mit strengen Anforderungen an Latenz und Parallelität.",
"Pro/moonshotai/Kimi-K2.5.description": "Kimi K2.5 ist ein Open-Source-natives multimodales Agentenmodell, basierend auf Kimi-K2-Base, trainiert mit etwa 1,5 Billionen gemischten Bild- und Text-Tokens. Das Modell verwendet eine MoE-Architektur mit insgesamt 1 Billion Parametern und 32 Milliarden aktiven Parametern, unterstützt ein Kontextfenster von 256K und integriert nahtlos visuelle und sprachliche Verständnisfähigkeiten.",
"Pro/zai-org/glm-4.7.description": "GLM-4.7 ist Zhipus neue Flaggschiff-Generation mit insgesamt 355 Milliarden Parametern und 32 Milliarden aktiven Parametern. Das Modell wurde umfassend in den Bereichen allgemeiner Dialog, logisches Denken und Agentenfähigkeiten verbessert. GLM-4.7 stärkt das Interleaved Thinking und führt Preserved Thinking sowie Turn-level Thinking ein.",
"Pro/zai-org/glm-4.7.description": "GLM-4.7 ist Zhipus neues Flaggschiffmodell der Generation mit 355 Milliarden Gesamt- und 32 Milliarden aktiven Parametern, vollständig aktualisiert in allgemeinem Dialog, logischem Denken und Agentenfähigkeiten. GLM-4.7 verbessert Interleaved Thinking und führt Preserved Thinking sowie Turn-level Thinking ein.",
"Pro/zai-org/glm-5.description": "GLM-5 ist Zhipus nächste Generation eines großen Sprachmodells, das sich auf komplexe Systementwicklung und lang andauernde Agentenaufgaben konzentriert. Die Modellparameter wurden auf 744 Milliarden (40 Milliarden aktiv) erweitert und integrieren DeepSeek Sparse Attention.",
"QwQ-32B-Preview.description": "Qwen QwQ ist ein experimentelles Forschungsmodell mit Fokus auf die Verbesserung logischer Schlussfolgerungen.",
"Qwen/QVQ-72B-Preview.description": "QVQ-72B-Preview ist ein Forschungsmodell von Qwen mit Schwerpunkt auf visuellem Denken. Es überzeugt durch seine Fähigkeit zur Analyse komplexer Szenen und zur Lösung visueller Mathematikaufgaben.",
"Qwen/QVQ-72B-Preview.description": "QVQ-72B-Preview ist ein Forschungsmodell von Qwen, das sich auf visuelles Denken konzentriert und Stärken in der komplexen Szenenverständnis und visuellen Mathematikproblemen aufweist.",
"Qwen/QwQ-32B-Preview.description": "Qwen QwQ ist ein experimentelles Forschungsmodell zur Verbesserung der KI-Logik und des Denkvermögens.",
"Qwen/QwQ-32B.description": "QwQ ist ein Modell für logisches Denken aus der Qwen-Familie. Im Vergleich zu standardmäßig instruktionstunierten Modellen bietet es erweitertes Denkvermögen, das die Leistung bei anspruchsvollen Aufgaben deutlich steigert. QwQ-32B ist ein mittelgroßes Modell, das mit führenden Denkmodellen wie DeepSeek-R1 und o1-mini konkurriert. Es verwendet RoPE, SwiGLU, RMSNorm und Attention QKV Bias, mit 64 Schichten und 40 Q-Attention-Köpfen (8 KV in GQA).",
"Qwen/Qwen-Image-Edit-2509.description": "Qwen-Image-Edit-2509 ist die neueste Bearbeitungsversion von Qwen-Image aus dem Qwen-Team. Basierend auf dem 20B Qwen-Image-Modell erweitert es die präzise Textdarstellung um Bildbearbeitungsfunktionen. Es nutzt eine Dual-Control-Architektur, bei der Eingaben an Qwen2.5-VL zur semantischen Steuerung und an einen VAE-Encoder zur visuellen Steuerung gesendet werden. Dadurch sind sowohl semantische als auch visuelle Bearbeitungen möglich. Es unterstützt lokale Änderungen (Hinzufügen/Entfernen/Modifizieren) sowie semantische Bearbeitungen wie IP-Erstellung und Stilübertragungen bei gleichzeitiger Wahrung der Bedeutung. Es erzielt SOTA-Ergebnisse in mehreren Benchmarks.",
@@ -207,11 +214,11 @@
"Skylark2-pro-turbo-8k.description": "Skylark Modell der 2. Generation. Skylark2-pro-turbo-8k bietet schnellere Inferenz bei geringeren Kosten mit einem 8K-Kontextfenster.",
"THUDM/GLM-4-32B-0414.description": "GLM-4-32B-0414 ist ein Open-Source-GLM-Modell der nächsten Generation mit 32 Milliarden Parametern, das in seiner Leistung mit OpenAI GPT und der DeepSeek V3/R1-Serie vergleichbar ist.",
"THUDM/GLM-4-9B-0414.description": "GLM-4-9B-0414 ist ein 9-Milliarden-Parameter-Modell, das auf den Techniken von GLM-4-32B basiert und eine leichtere Bereitstellung ermöglicht. Es überzeugt bei der Codegenerierung, Webdesign, SVG-Erstellung und suchbasiertem Schreiben.",
"THUDM/GLM-4.1V-9B-Thinking.description": "GLM-4.1V-9B-Thinking ist ein quelloffenes VLM von Zhipu AI und dem KEG-Labor der Tsinghua-Universität, das für komplexe multimodale Kognition entwickelt wurde. Aufbauend auf GLM-4-9B-0414 integriert es Chain-of-Thought-Reasoning und Reinforcement Learning, um die modalübergreifende Argumentation und Stabilität deutlich zu verbessern.",
"THUDM/GLM-4.1V-9B-Thinking.description": "GLM-4.1V-9B-Thinking ist ein Open-Source-VLM von Zhipu AI und dem Tsinghua KEG Lab, entwickelt für komplexe multimodale Kognition. Basierend auf GLM-4-9B-0414 fügt es Chain-of-Thought-Reasoning und RL hinzu, um die cross-modale Argumentation und Stabilität erheblich zu verbessern.",
"THUDM/GLM-Z1-32B-0414.description": "GLM-Z1-32B-0414 ist ein Modell für tiefgehende Argumentation, das auf GLM-4-32B-0414 basiert und mit Cold-Start-Daten sowie erweitertem Reinforcement Learning weitertrainiert wurde. Es wurde zusätzlich auf Mathematik, Code und Logik trainiert und verbessert die Fähigkeiten zur Lösung komplexer Aufgaben erheblich.",
"THUDM/GLM-Z1-9B-0414.description": "GLM-Z1-9B-0414 ist ein kompaktes GLM-Modell mit 9 Milliarden Parametern, das die Stärken von Open-Source-Modellen beibehält und gleichzeitig eine beeindruckende Leistung bietet. Es überzeugt besonders bei mathematischer Argumentation und allgemeinen Aufgaben und ist führend in seiner Größenklasse unter offenen Modellen.",
"THUDM/glm-4-9b-chat.description": "GLM-4-9B-Chat ist das quelloffene GLM-4-Modell von Zhipu AI. Es zeigt starke Leistungen in Semantik, Mathematik, Argumentation, Code und Wissen. Neben mehrstufigem Dialog unterstützt es Web-Browsing, Codeausführung, benutzerdefinierte Tool-Aufrufe und Langtext-Argumentation. Es unterstützt 26 Sprachen (darunter Chinesisch, Englisch, Japanisch, Koreanisch, Deutsch) und erzielt gute Ergebnisse bei AlignBench-v2, MT-Bench, MMLU und C-Eval. Es unterstützt Kontexte bis zu 128.000 Tokens für akademische und geschäftliche Anwendungen.",
"Tongyi-Zhiwen/QwenLong-L1-32B.description": "QwenLong-L1-32B ist das erste Long-Context-Reasoning-Modell (LRM), das mit Reinforcement Learning trainiert wurde und für Langtext-Argumentation optimiert ist. Durch progressives Kontextwachstum im RL gelingt ein stabiler Übergang von kurzen zu langen Kontexten. Es übertrifft OpenAI-o3-mini und Qwen3-235B-A22B in sieben Benchmarks für Langkontext-Dokumentfragen und konkurriert mit Claude-3.7-Sonnet-Thinking. Besonders stark ist es in Mathematik, Logik und mehrstufiger Argumentation.",
"Tongyi-Zhiwen/QwenLong-L1-32B.description": "QwenLong-L1-32B ist das erste Modell für langes Kontextdenken (LRM), das mit RL trainiert wurde und für langes Textdenken optimiert ist. Sein progressives Kontext-Erweiterungs-RL ermöglicht eine stabile Übertragung von kurzen zu langen Kontexten. Es übertrifft OpenAI-o3-mini und Qwen3-235B-A22B in sieben Benchmarks für langes Kontext-Dokument-QA und konkurriert mit Claude-3.7-Sonnet-Thinking. Besonders stark ist es in Mathematik, Logik und mehrstufigem Denken.",
"Yi-34B-Chat.description": "Yi-1.5-34B bewahrt die starken allgemeinen Sprachfähigkeiten der Serie und verbessert durch inkrementelles Training mit 500 Milliarden hochwertigen Tokens die Leistungen in Mathematik, Logik und Programmierung deutlich.",
"abab5.5-chat.description": "Entwickelt für produktive Szenarien mit komplexer Aufgabenverarbeitung und effizienter Textgenerierung für den professionellen Einsatz.",
"abab5.5s-chat.description": "Optimiert für chinesische Persona-Chats und liefert hochwertige chinesische Dialoge für vielfältige Anwendungen.",
@@ -306,12 +313,12 @@
"claude-haiku-4-5-20251001.description": "Claude Haiku 4.5 ist das schnellste und intelligenteste Haiku-Modell von Anthropic, mit blitzschneller Geschwindigkeit und erweitertem Denken.",
"claude-haiku-4.5.description": "Claude Haiku 4.5 ist ein schnelles und effizientes Modell für vielfältige Aufgaben.",
"claude-opus-4-1-20250805-thinking.description": "Claude Opus 4.1 Thinking ist eine erweiterte Variante, die ihren Denkprozess offenlegen kann.",
"claude-opus-4-1-20250805.description": "Claude Opus 4.1 ist das neueste und leistungsfähigste Modell von Anthropic für hochkomplexe Aufgaben, herausragend in Leistung, Intelligenz, Sprachgewandtheit und Verständnis.",
"claude-opus-4-20250514.description": "Claude Opus 4 ist das leistungsstärkste Modell von Anthropic für hochkomplexe Aufgaben, herausragend in Leistung, Intelligenz, Sprachgewandtheit und Verständnis.",
"claude-opus-4-1-20250805.description": "Claude Opus 4.1 ist das neueste und leistungsfähigste Modell von Anthropic für hochkomplexe Aufgaben, das in Leistung, Intelligenz, Sprachgewandtheit und Verständnis herausragt.",
"claude-opus-4-20250514.description": "Claude Opus 4 ist das leistungsstärkste Modell von Anthropic für hochkomplexe Aufgaben, das in Leistung, Intelligenz, Sprachgewandtheit und Verständnis herausragt.",
"claude-opus-4-5-20251101.description": "Claude Opus 4.5 ist das Flaggschiffmodell von Anthropic. Es kombiniert herausragende Intelligenz mit skalierbarer Leistung und ist ideal für komplexe Aufgaben, die höchste Qualität bei Antworten und logischem Denken erfordern.",
"claude-opus-4-6.description": "Claude Opus 4.6 ist das intelligenteste Modell von Anthropic für die Erstellung von Agenten und Programmierung.",
"claude-opus-4-6.description": "Claude Opus 4.6 ist das intelligenteste Modell von Anthropic für die Entwicklung von Agenten und Programmierung.",
"claude-sonnet-4-20250514-thinking.description": "Claude Sonnet 4 Thinking kann nahezu sofortige Antworten oder schrittweises Denken mit sichtbarem Prozess erzeugen.",
"claude-sonnet-4-20250514.description": "Claude Sonnet 4 ist das bisher intelligenteste Modell von Anthropic, bietet nahezu sofortige Antworten oder erweitertes schrittweises Denken mit fein abgestimmter Kontrolle für API-Nutzer.",
"claude-sonnet-4-20250514.description": "Claude Sonnet 4 ist das bisher intelligenteste Modell von Anthropic, das nahezu sofortige Antworten oder erweitertes schrittweises Denken mit fein abgestimmter Kontrolle für API-Nutzer bietet.",
"claude-sonnet-4-5-20250929.description": "Claude Sonnet 4.5 ist das bisher intelligenteste Modell von Anthropic.",
"claude-sonnet-4-6.description": "Claude Sonnet 4.6 ist die beste Kombination aus Geschwindigkeit und Intelligenz von Anthropic.",
"claude-sonnet-4.description": "Claude Sonnet 4 ist die neueste Generation mit verbesserter Leistung in allen Aufgabenbereichen.",
@@ -370,7 +377,7 @@
"deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B.description": "Die destillierten Modelle von DeepSeek-R1 nutzen RL und Cold-Start-Daten zur Verbesserung des Denkvermögens und setzen neue Maßstäbe für offene Multi-Task-Modelle.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-14B.description": "Die destillierten Modelle von DeepSeek-R1 nutzen RL und Cold-Start-Daten zur Verbesserung des Denkvermögens und setzen neue Maßstäbe für offene Multi-Task-Modelle.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-32B.description": "DeepSeek-R1-Distill-Qwen-32B ist aus Qwen2.5-32B destilliert und auf 800.000 kuratierten DeepSeek-R1-Beispielen feinabgestimmt. Es überzeugt in Mathematik, Programmierung und logischem Denken mit starken Ergebnissen bei AIME 2024, MATH-500 (94,3% Genauigkeit) und GPQA Diamond.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "DeepSeek-R1-Distill-Qwen-7B ist aus Qwen2.5-Math-7B destilliert und auf 800.000 kuratierten DeepSeek-R1-Beispielen feinabgestimmt. Es erzielt starke Leistungen mit 92,8% bei MATH-500, 55,5% bei AIME 2024 und einem CodeForces-Rating von 1189 für ein 7B-Modell.",
"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B.description": "DeepSeek-R1-Distill-Qwen-7B wurde aus Qwen2.5-Math-7B destilliert und auf 800.000 kuratierten DeepSeek-R1-Proben feinabgestimmt. Es erzielt starke Leistungen mit 92,8 % bei MATH-500, 55,5 % bei AIME 2024 und einer CodeForces-Bewertung von 1189 für ein 7B-Modell.",
"deepseek-ai/DeepSeek-R1.description": "DeepSeek-R1 verbessert das Denkvermögen durch RL und Cold-Start-Daten, setzt neue Maßstäbe für offene Multi-Task-Modelle und übertrifft OpenAI-o1-mini.",
"deepseek-ai/DeepSeek-V2.5.description": "DeepSeek-V2.5 ist ein Upgrade von DeepSeek-V2-Chat und DeepSeek-Coder-V2-Instruct und kombiniert allgemeine und Programmierfähigkeiten. Es verbessert das Schreiben und das Befolgen von Anweisungen für eine bessere Präferenzanpassung und zeigt deutliche Fortschritte bei AlpacaEval 2.0, ArenaHard, AlignBench und MT-Bench.",
"deepseek-ai/DeepSeek-V3.1-Terminus.description": "DeepSeek-V3.1-Terminus ist ein aktualisiertes V3.1-Modell, das als hybrides Agenten-LLM positioniert ist. Es behebt gemeldete Probleme, verbessert die Stabilität und Sprachkonsistenz und reduziert gemischte chinesisch/englische Ausgaben sowie fehlerhafte Zeichen. Es integriert Denk- und Nicht-Denk-Modi mit Chat-Vorlagen für flexibles Umschalten. Zudem verbessert es die Leistung von Code- und Suchagenten für zuverlässigere Toolnutzung und mehrstufige Aufgaben.",
@@ -383,7 +390,7 @@
"deepseek-ai/deepseek-v3.1.description": "DeepSeek V3.1 ist ein Next-Gen-Denkmodell mit stärkerem komplexem Denken und Chain-of-Thought für tiefgreifende Analyseaufgaben.",
"deepseek-ai/deepseek-v3.2.description": "DeepSeek V3.2 ist ein Next-Gen-Modell für logisches Denken mit stärkeren Fähigkeiten für komplexes Denken und Kettenlogik.",
"deepseek-ai/deepseek-vl2.description": "DeepSeek-VL2 ist ein MoE Vision-Language-Modell auf Basis von DeepSeekMoE-27B mit sparsamer Aktivierung. Es erreicht starke Leistung mit nur 4,5B aktiven Parametern und überzeugt bei visuellen QA-Aufgaben, OCR, Dokument-/Tabellen-/Diagrammverständnis und visueller Verankerung.",
"deepseek-chat.description": "DeepSeek V3.2 balanciert Argumentation und Ausgabelänge für tägliche QA- und Agentenaufgaben. Öffentliche Benchmarks erreichen GPT-5-Niveau und es ist das erste Modell, das Denken in die Werkzeugnutzung integriert, führend in Open-Source-Agentenbewertungen.",
"deepseek-chat.description": "DeepSeek V3.2 balanciert logisches Denken und Ausgabelänge für tägliche QA- und Agentenaufgaben. Öffentliche Benchmarks erreichen GPT-5-Niveau, und es ist das erste Modell, das Denken in die Werkzeugnutzung integriert und führende Open-Source-Agentenbewertungen erzielt.",
"deepseek-coder-33B-instruct.description": "DeepSeek Coder 33B ist ein Code-Sprachmodell, trainiert auf 2B Tokens (87% Code, 13% chinesisch/englischer Text). Es bietet ein 16K-Kontextfenster und Fill-in-the-Middle-Aufgaben für projektweite Codevervollständigung und Snippet-Ergänzung.",
"deepseek-coder-v2.description": "DeepSeek Coder V2 ist ein Open-Source-MoE-Code-Modell mit starker Leistung bei Programmieraufgaben, vergleichbar mit GPT-4 Turbo.",
"deepseek-coder-v2:236b.description": "DeepSeek Coder V2 ist ein Open-Source-MoE-Code-Modell mit starker Leistung bei Programmieraufgaben, vergleichbar mit GPT-4 Turbo.",
@@ -406,7 +413,7 @@
"deepseek-r1-fast-online.description": "DeepSeek R1 Schnellversion mit Echtzeit-Websuche kombiniert 671B-Fähigkeiten mit schneller Reaktion.",
"deepseek-r1-online.description": "DeepSeek R1 Vollversion mit 671B Parametern und Echtzeit-Websuche bietet stärkeres Verständnis und bessere Generierung.",
"deepseek-r1.description": "DeepSeek-R1 nutzt Cold-Start-Daten vor dem RL und erreicht vergleichbare Leistungen wie OpenAI-o1 bei Mathematik, Programmierung und logischem Denken.",
"deepseek-reasoner.description": "DeepSeek V3.2 Thinking ist ein tiefgründiges Argumentationsmodell, das vor der Ausgabe eine Gedankenverkettung generiert, um höhere Genauigkeit zu erzielen, mit Spitzenwettbewerbsergebnissen und Argumentationsfähigkeiten vergleichbar mit Gemini-3.0-Pro.",
"deepseek-reasoner.description": "DeepSeek V3.2 Thinking ist ein tiefes Argumentationsmodell, das vor der Ausgabe eine Gedankenkette generiert, um höhere Genauigkeit zu erzielen, mit Spitzenwettbewerbsergebnissen und Argumentationsfähigkeiten vergleichbar mit Gemini-3.0-Pro.",
"deepseek-v2.description": "DeepSeek V2 ist ein effizientes MoE-Modell für kostengünstige Verarbeitung.",
"deepseek-v2:236b.description": "DeepSeek V2 236B ist das codefokussierte Modell von DeepSeek mit starker Codegenerierung.",
"deepseek-v3-0324.description": "DeepSeek-V3-0324 ist ein MoE-Modell mit 671B Parametern und herausragenden Stärken in Programmierung, technischer Kompetenz, Kontextverständnis und Langtextverarbeitung.",
@@ -417,7 +424,7 @@
"deepseek-v3.2-exp.description": "deepseek-v3.2-exp führt Sparse Attention ein, um die Effizienz beim Training und bei der Inferenz bei langen Texten zu verbessern zu einem günstigeren Preis als deepseek-v3.1.",
"deepseek-v3.2-speciale.description": "Bei hochkomplexen Aufgaben übertrifft das Speciale-Modell die Standardversion deutlich, verbraucht jedoch erheblich mehr Tokens und verursacht höhere Kosten. Derzeit ist DeepSeek-V3.2-Speciale nur für Forschungszwecke vorgesehen, unterstützt keine Werkzeugaufrufe und wurde nicht speziell für alltägliche Konversations- oder Schreibaufgaben optimiert.",
"deepseek-v3.2-think.description": "DeepSeek V3.2 Think ist ein vollwertiges Denkmodell mit stärkerer langkettiger Argumentation.",
"deepseek-v3.2.description": "DeepSeek-V3.2 ist das erste hybride Reasoning-Modell von DeepSeek, das Denkprozesse in die Werkzeugnutzung integriert. Es verwendet eine effiziente Architektur zur Reduzierung des Rechenaufwands, groß angelegte Verstärkungslernen zur Leistungssteigerung und synthetische Aufgabendaten zur besseren Generalisierung. Diese Kombination ermöglicht eine Leistung vergleichbar mit GPT-5-High bei deutlich kürzeren Ausgaben, was Rechenkosten und Wartezeiten für Nutzer erheblich reduziert.",
"deepseek-v3.2.description": "DeepSeek-V3.2 ist DeepSeeks neuestes Programmiermodell mit starken Argumentationsfähigkeiten.",
"deepseek-v3.description": "DeepSeek-V3 ist ein leistungsstarkes MoE-Modell mit insgesamt 671 Milliarden Parametern und 37 Milliarden aktiven Parametern pro Token.",
"deepseek-vl2-small.description": "DeepSeek VL2 Small ist eine leichtgewichtige multimodale Version für ressourcenbeschränkte und hochparallele Anwendungen.",
"deepseek-vl2.description": "DeepSeek VL2 ist ein multimodales Modell für Bild-Text-Verständnis und fein abgestimmte visuelle Fragebeantwortung.",
@@ -506,8 +513,8 @@
"ernie-x1-turbo-32k.description": "ERNIE X1 Turbo 32K ist ein schnelles Denkmodell mit 32K Kontext für komplexe Schlussfolgerungen und mehrstufige Gespräche.",
"ernie-x1.1-preview.description": "ERNIE X1.1 Preview ist ein Vorschau-Modell mit Denkfähigkeit zur Bewertung und zum Testen.",
"ernie-x1.1.description": "ERNIE X1.1 ist ein Vorschau-Denkmodell für Evaluierung und Tests.",
"fal-ai/bytedance/seedream/v4.5.description": "Seedream 4.5, entwickelt vom ByteDance Seed-Team, unterstützt die Bearbeitung und Komposition mehrerer Bilder. Es bietet verbesserte Konsistenz des Motivs, präzises Befolgen von Anweisungen, räumliches Logikverständnis, ästhetischen Ausdruck, Posterlayout und Logodesign mit hochpräziser Text-Bild-Wiedergabe.",
"fal-ai/bytedance/seedream/v4.description": "Seedream 4.0, entwickelt von ByteDance Seed, unterstützt Text- und Bildeingaben für hochgradig kontrollierbare, qualitativ hochwertige Bildgenerierung aus Eingabeaufforderungen.",
"fal-ai/bytedance/seedream/v4.5.description": "Seedream 4.5, entwickelt vom ByteDance Seed-Team, unterstützt die Bearbeitung und Komposition mehrerer Bilder. Es bietet verbesserte Konsistenz des Motivs, präzise Befolgung von Anweisungen, räumliches Logikverständnis, ästhetischen Ausdruck, Posterlayout und Logodesign mit hochpräziser Text-Bild-Wiedergabe.",
"fal-ai/bytedance/seedream/v4.description": "Seedream 4.0, entwickelt von ByteDance Seed, unterstützt Text- und Bildeingaben für hochkontrollierbare, qualitativ hochwertige Bildgenerierung aus Eingabeaufforderungen.",
"fal-ai/flux-kontext/dev.description": "FLUX.1-Modell mit Fokus auf Bildbearbeitung, unterstützt Text- und Bildeingaben.",
"fal-ai/flux-pro/kontext.description": "FLUX.1 Kontext [pro] akzeptiert Texte und Referenzbilder als Eingabe und ermöglicht gezielte lokale Bearbeitungen sowie komplexe globale Szenentransformationen.",
"fal-ai/flux/krea.description": "Flux Krea [dev] ist ein Bildgenerierungsmodell mit ästhetischer Ausrichtung auf realistischere, natürliche Bilder.",
@@ -515,8 +522,8 @@
"fal-ai/hunyuan-image/v3.description": "Ein leistungsstarkes natives multimodales Bildgenerierungsmodell.",
"fal-ai/imagen4/preview.description": "Hochwertiges Bildgenerierungsmodell von Google.",
"fal-ai/nano-banana.description": "Nano Banana ist das neueste, schnellste und effizienteste native multimodale Modell von Google. Es ermöglicht Bildgenerierung und -bearbeitung im Dialog.",
"fal-ai/qwen-image-edit.description": "Ein professionelles Bildbearbeitungsmodell des Qwen-Teams, das semantische und optische Bearbeitungen, präzise chinesische/englische Textbearbeitung, Stilübertragung, Drehung und mehr unterstützt.",
"fal-ai/qwen-image.description": "Ein leistungsstarkes Bildgenerierungsmodell des Qwen-Teams mit starker chinesischer Textrendering und vielfältigen visuellen Stilen.",
"fal-ai/qwen-image-edit.description": "Ein professionelles Bildbearbeitungsmodell des Qwen-Teams, das semantische und Erscheinungsbearbeitungen, präzise chinesische/englische Textbearbeitung, Stiltransfer, Rotation und mehr unterstützt.",
"fal-ai/qwen-image.description": "Ein leistungsstarkes Bildgenerierungsmodell des Qwen-Teams mit starker chinesischer Textrendering-Fähigkeit und vielfältigen visuellen Stilen.",
"flux-1-schnell.description": "Ein Text-zu-Bild-Modell mit 12 Milliarden Parametern von Black Forest Labs, das latente adversariale Diffusionsdistillation nutzt, um hochwertige Bilder in 14 Schritten zu erzeugen. Es konkurriert mit geschlossenen Alternativen und ist unter Apache-2.0 für persönliche, Forschungs- und kommerzielle Nutzung verfügbar.",
"flux-dev.description": "FLUX.1 [dev] ist ein Modell mit offenen Gewichten für nicht-kommerzielle Nutzung. Es bietet nahezu professionelle Bildqualität und Befolgung von Anweisungen bei effizienterer Nutzung von Ressourcen im Vergleich zu Standardmodellen gleicher Größe.",
"flux-kontext-max.description": "Modernste kontextuelle Bildgenerierung und -bearbeitung, kombiniert Text und Bilder für präzise, kohärente Ergebnisse.",
@@ -563,7 +570,7 @@
"gemini-3-pro-image-preview:image.description": "Gemini 3 Pro Image (Nano Banana Pro) ist Googles Bildgenerierungsmodell und unterstützt auch multimodale Chats.",
"gemini-3-pro-preview.description": "Gemini 3 Pro ist Googles leistungsstärkstes Agenten- und Vibe-Coding-Modell. Es bietet reichhaltigere visuelle Inhalte und tiefere Interaktionen auf Basis modernster logischer Fähigkeiten.",
"gemini-3.1-flash-image-preview.description": "Gemini 3.1 Flash Image (Nano Banana 2) ist Googles schnellstes natives Bildgenerierungsmodell mit Denkunterstützung, konversationaler Bildgenerierung und -bearbeitung.",
"gemini-3.1-flash-image-preview:image.description": "Gemini 3.1 Flash Image (Nano Banana 2) liefert Bildqualität auf Pro-Niveau mit Flash-Geschwindigkeit und unterstützt multimodale Chats.",
"gemini-3.1-flash-image-preview:image.description": "Gemini 3.1 Flash Image (Nano Banana 2) liefert Pro-Level-Bildqualität mit Flash-Geschwindigkeit und unterstützt multimodale Chats.",
"gemini-3.1-flash-lite-preview.description": "Gemini 3.1 Flash-Lite Preview ist Googles kosteneffizientestes multimodales Modell, optimiert für hochvolumige agentische Aufgaben, Übersetzung und Datenverarbeitung.",
"gemini-3.1-pro-preview.description": "Gemini 3.1 Pro Preview verbessert Gemini 3 Pro mit erweiterten Fähigkeiten für logisches Denken und unterstützt mittleres Denklevel.",
"gemini-flash-latest.description": "Neueste Version von Gemini Flash",
@@ -798,7 +805,7 @@
"kimi-k2-thinking-turbo.description": "Hochgeschwindigkeitsvariante von K2 mit erweitertem Denkvermögen, 256k Kontext, starkem logischen Denken und einer Ausgabe von 60100 Token/Sekunde.",
"kimi-k2-thinking.description": "kimi-k2-thinking ist ein Denkmodell von Moonshot AI mit allgemeinen Agenten- und Denkfähigkeiten. Es glänzt durch tiefes logisches Denken und kann komplexe Probleme durch mehrstufige Werkzeugnutzung lösen.",
"kimi-k2-turbo-preview.description": "kimi-k2 ist ein MoE-Grundlagenmodell mit starken Fähigkeiten in den Bereichen Programmierung und Agentenfunktionen (1T Gesamtparameter, 32B aktiv) und übertrifft andere gängige Open-Source-Modelle in den Bereichen logisches Denken, Programmierung, Mathematik und Agenten-Benchmarks.",
"kimi-k2.5.description": "Kimi K2.5 ist das leistungsfähigste Kimi-Modell und bietet Open-Source-SOTA in Agentenaufgaben, Programmierung und visuellem Verständnis. Es unterstützt multimodale Eingaben sowie Denk- und Nicht-Denk-Modi.",
"kimi-k2.5.description": "Kimi K2.5 ist Kimi's vielseitigstes Modell bisher, mit einer nativen multimodalen Architektur, die sowohl visuelle als auch Texteingaben unterstützt, 'Denk'- und 'Nicht-Denk'-Modi sowie Konversations- und Agentenaufgaben.",
"kimi-k2.description": "Kimi-K2 ist ein MoE-Basismodell von Moonshot AI mit starken Fähigkeiten in den Bereichen Programmierung und Agentenfunktionen, insgesamt 1T Parameter mit 32B aktiven. In Benchmarks zu allgemeinem logischen Denken, Programmierung, Mathematik und Agentenaufgaben übertrifft es andere gängige Open-Source-Modelle.",
"kimi-k2:1t.description": "Kimi K2 ist ein großes MoE-LLM von Moonshot AI mit insgesamt 1T Parametern und 32B aktiven pro Durchlauf. Es ist für Agentenfunktionen wie fortgeschrittene Werkzeugnutzung, logisches Denken und Codegenerierung optimiert.",
"kuaishou/kat-coder-pro-v1.description": "KAT-Coder-Pro-V1 (zeitlich begrenzt kostenlos) konzentriert sich auf Codeverständnis und Automatisierung für effiziente Programmieragenten.",
@@ -960,7 +967,7 @@
"moonshot-v1-32k.description": "Moonshot V1 32K unterstützt 32.768 Tokens für mittellange Kontexte ideal für lange Dokumente und komplexe Dialoge in der Inhaltserstellung, Berichterstattung und Chat-Systemen.",
"moonshot-v1-8k-vision-preview.description": "Kimi Vision-Modelle (einschließlich moonshot-v1-8k-vision-preview/moonshot-v1-32k-vision-preview/moonshot-v1-128k-vision-preview) können Bildinhalte wie Text, Farben und Objektformen verstehen.",
"moonshot-v1-8k.description": "Moonshot V1 8K ist für die Generierung kurzer Texte mit effizienter Leistung optimiert und verarbeitet 8.192 Tokens ideal für kurze Chats, Notizen und schnelle Inhalte.",
"moonshotai/Kimi-Dev-72B.description": "Kimi-Dev-72B ist ein quelloffenes Code-LLM, das mit großflächigem RL optimiert wurde, um robuste, produktionsreife Patches zu erzeugen. Es erreicht 60,4 % auf SWE-bench Verified und setzt damit einen neuen Rekord für Open-Modelle bei automatisierten Softwareentwicklungsaufgaben wie Bugfixing und Code-Review.",
"moonshotai/Kimi-Dev-72B.description": "Kimi-Dev-72B ist ein Open-Source-Code-LLM, optimiert durch großskaliges RL, um robuste, produktionsreife Patches zu erstellen. Es erzielt 60,4 % auf SWE-bench Verified und setzt einen neuen Rekord für automatisierte Software-Engineering-Aufgaben wie Fehlerbehebung und Code-Review.",
"moonshotai/Kimi-K2-Instruct-0905.description": "Kimi K2-Instruct-0905 ist das neueste und leistungsstärkste Modell der Kimi K2-Reihe. Es handelt sich um ein MoE-Spitzenmodell mit insgesamt 1T und 32B aktiven Parametern. Zu den Hauptmerkmalen gehören eine stärkere agentenbasierte Codierungsintelligenz mit deutlichen Verbesserungen bei Benchmarks und realen Agentenaufgaben sowie eine verbesserte Ästhetik und Benutzerfreundlichkeit im Frontend-Code.",
"moonshotai/Kimi-K2-Thinking.description": "Kimi K2 Thinking ist das neueste und leistungsstärkste Open-Source-Denkmodell. Es erweitert die Tiefe des mehrstufigen Denkens erheblich und gewährleistet stabile Werkzeugnutzung über 200300 aufeinanderfolgende Aufrufe, wobei neue Rekorde bei Humanity's Last Exam (HLE), BrowseComp und anderen Benchmarks aufgestellt werden. Es zeichnet sich in den Bereichen Programmierung, Mathematik, Logik und Agentenszenarien aus. Basierend auf einer MoE-Architektur mit ~1 Billion Gesamtparametern unterstützt es ein 256K-Kontextfenster und Werkzeugaufrufe.",
"moonshotai/kimi-k2-0711.description": "Kimi K2 0711 ist die Instruct-Variante der Kimi-Serie, geeignet für hochwertigen Code und Werkzeugnutzung.",
@@ -1163,6 +1170,7 @@
"qwen3-coder-next.description": "Next-Gen Qwen-Coder optimiert für komplexe Multi-Datei-Codegenerierung, Debugging und hochdurchsatzfähige Agenten-Workflows. Entwickelt für starke Werkzeugintegration und verbesserte Leistung im logischen Denken.",
"qwen3-coder-plus.description": "Qwen-Code-Modell. Die neueste Qwen3-Coder-Serie basiert auf Qwen3 und bietet starke Fähigkeiten für Coding-Agenten, Werkzeugnutzung und Interaktion mit Umgebungen für autonomes Programmieren, mit exzellenter Codeleistung und solider Allgemeinkompetenz.",
"qwen3-coder:480b.description": "Alibabas leistungsstarkes Langkontextmodell für Agenten- und Programmieraufgaben.",
"qwen3-max-2026-01-23.description": "Qwen3 Max: Bestleistendes Qwen-Modell für komplexe, mehrstufige Programmieraufgaben mit Unterstützung für logisches Denken.",
"qwen3-max-preview.description": "Leistungsstärkstes Qwen-Modell für komplexe, mehrstufige Aufgaben. Die Vorschau unterstützt Denkprozesse.",
"qwen3-max.description": "Qwen3 Max-Modelle bieten große Fortschritte gegenüber der 2.5-Serie in allgemeiner Fähigkeit, chinesisch/englischem Verständnis, komplexer Anweisungsbefolgung, offenen subjektiven Aufgaben, Mehrsprachigkeit und Werkzeugnutzung bei weniger Halluzinationen. Das neueste qwen3-max verbessert agentisches Programmieren und Werkzeugnutzung gegenüber qwen3-max-preview. Diese Version erreicht SOTA-Niveau und zielt auf komplexere Agentenanforderungen.",
"qwen3-next-80b-a3b-instruct.description": "Nächste Generation des Qwen3 Open-Source-Modells ohne Denkfunktion. Im Vergleich zur vorherigen Version (Qwen3-235B-A22B-Instruct-2507) bietet es besseres chinesisches Verständnis, stärkere logische Schlussfolgerung und verbesserte Textgenerierung.",
@@ -1192,8 +1200,8 @@
"qwq.description": "QwQ ist ein Schlussfolgerungsmodell aus der Qwen-Familie. Im Vergleich zu standardmäßig instruktionstunierten Modellen bietet es überlegene Denk- und Schlussfolgerungsfähigkeiten, die die Leistung bei nachgelagerten Aufgaben deutlich verbessern insbesondere bei schwierigen Problemen. QwQ-32B ist ein mittelgroßes Modell, das mit führenden Schlussfolgerungsmodellen wie DeepSeek-R1 und o1-mini mithalten kann.",
"qwq_32b.description": "Mittelgroßes Schlussfolgerungsmodell aus der Qwen-Familie. Im Vergleich zu standardmäßig instruktionstunierten Modellen steigern QwQs Denk- und Schlussfolgerungsfähigkeiten die Leistung bei nachgelagerten Aufgaben deutlich insbesondere bei schwierigen Problemen.",
"r1-1776.description": "R1-1776 ist eine nachtrainierte Variante von DeepSeek R1, die darauf ausgelegt ist, unzensierte, objektive und faktenbasierte Informationen bereitzustellen.",
"seedance-1-5-pro-251215.description": "Seedance 1.5 Pro von ByteDance unterstützt Text-zu-Video, Bild-zu-Video (erster Frame, erster+letzter Frame) und Audiogenerierung synchronisiert mit visuellen Inhalten.",
"seedream-5-0-260128.description": "ByteDance-Seedream-5.0-lite von BytePlus bietet webgestützte Generierung für Echtzeitinformationen, verbesserte Interpretation komplexer Eingabeaufforderungen und verbesserte Konsistenz von Referenzen für professionelle visuelle Kreationen.",
"seedance-1-5-pro-251215.description": "Seedance 1.5 Pro von ByteDance unterstützt Text-zu-Video, Bild-zu-Video (erstes Bild, erstes+letztes Bild) und Audiogenerierung synchronisiert mit visuellen Elementen.",
"seedream-5-0-260128.description": "ByteDance-Seedream-5.0-lite von BytePlus bietet webabfrage-unterstützte Generierung für Echtzeitinformationen, verbesserte Interpretation komplexer Eingabeaufforderungen und verbesserte Konsistenz von Referenzen für professionelle visuelle Kreationen.",
"solar-mini-ja.description": "Solar Mini (Ja) erweitert Solar Mini mit einem Fokus auf Japanisch und behält dabei eine effiziente und starke Leistung in Englisch und Koreanisch bei.",
"solar-mini.description": "Solar Mini ist ein kompaktes LLM, das GPT-3.5 übertrifft. Es bietet starke mehrsprachige Fähigkeiten in Englisch und Koreanisch und ist eine effiziente Lösung mit kleinem Ressourcenbedarf.",
"solar-pro.description": "Solar Pro ist ein hochintelligentes LLM von Upstage, das auf Befolgen von Anweisungen auf einer einzelnen GPU ausgelegt ist und IFEval-Werte über 80 erreicht. Derzeit wird Englisch unterstützt; die vollständige Veröffentlichung mit erweitertem Sprachsupport und längeren Kontexten war für November 2024 geplant.",
@@ -1229,7 +1237,7 @@
"step-3.5-flash.description": "Stepfuns Flaggschiff-Sprachargumentationsmodell. Dieses Modell verfügt über erstklassige Argumentationsfähigkeiten und schnelle sowie zuverlässige Ausführungskapazitäten. Es kann komplexe Aufgaben wie logisches Denken, Mathematik, Softwareentwicklung und tiefgehende Forschung zerlegen und planen, Werkzeuge schnell und zuverlässig aufrufen, um Aufgaben auszuführen, und ist in verschiedenen komplexen Aufgaben kompetent.",
"step-3.description": "Dieses Modell verfügt über starke visuelle Wahrnehmung und komplexe Schlussfolgerungsfähigkeiten. Es verarbeitet domänenübergreifendes Wissen, analysiert Mathematik und visuelle Inhalte gemeinsam und bewältigt eine Vielzahl alltäglicher visueller Analyseaufgaben.",
"step-r1-v-mini.description": "Ein Schlussfolgerungsmodell mit starkem Bildverständnis, das Bilder und Texte verarbeiten und anschließend durch tiefes Denken Text generieren kann. Es glänzt im visuellen Denken und liefert Spitzenleistungen in Mathematik, Programmierung und Textverständnis mit einem Kontextfenster von 100K.",
"stepfun-ai/step3.description": "Step3 ist ein hochmodernes multimodales Schlussfolgerungsmodell von StepFun, basierend auf einer MoE-Architektur mit insgesamt 321B und 38B aktiven Parametern. Sein End-to-End-Design minimiert die Dekodierungskosten und liefert erstklassige Vision-Language-Schlussfolgerungen. Dank MFA- und AFD-Design bleibt es sowohl auf High-End- als auch auf Low-End-Beschleunigern effizient. Das Pretraining umfasst über 20T Text-Tokens und 4T Bild-Text-Tokens in vielen Sprachen. Es erreicht führende Leistungen bei offenen Modellen in Mathematik, Code und multimodalen Benchmarks.",
"stepfun-ai/step3.description": "Step3 ist ein hochmodernes multimodales Argumentationsmodell von StepFun, basierend auf einer MoE-Architektur mit 321 Milliarden Gesamt- und 38 Milliarden aktiven Parametern. Sein End-to-End-Design minimiert Dekodierungskosten und liefert erstklassige Vision-Language-Argumentation. Mit MFA- und AFD-Design bleibt es effizient auf sowohl Flaggschiff- als auch Low-End-Beschleunigern. Das Pretraining verwendet über 20 Billionen Text-Tokens und 4 Billionen Bild-Text-Tokens in vielen Sprachen. Es erreicht führende Open-Model-Leistungen bei Mathematik-, Code- und multimodalen Benchmarks.",
"taichu4_vl_2b_nothinking.description": "Die No-Thinking-Version des Taichu4.0-VL 2B-Modells bietet geringeren Speicherverbrauch, ein leichtes Design, schnelle Reaktionsgeschwindigkeit und starke multimodale Verständnisfähigkeiten.",
"taichu4_vl_32b.description": "Die Thinking-Version des Taichu4.0-VL 32B-Modells eignet sich für komplexe multimodale Verständnis- und Denkaufgaben und zeigt herausragende Leistung in multimodaler mathematischer Logik, multimodalen Agentenfähigkeiten und allgemeinem Bild- und visuellen Verständnis.",
"taichu4_vl_32b_nothinking.description": "Die No-Thinking-Version des Taichu4.0-VL 32B-Modells ist für komplexe Bild- und Textverständnis- sowie visuelle Wissens-QA-Szenarien konzipiert und zeichnet sich durch Bildunterschriftenerstellung, visuelle Fragenbeantwortung, Videoverständnis und visuelle Lokalisierungsaufgaben aus.",
@@ -1316,7 +1324,7 @@
"zai-org/GLM-4.5-Air.description": "GLM-4.5-Air ist ein Basismodell für Agentenanwendungen mit Mixture-of-Experts-Architektur. Es ist optimiert für Toolnutzung, Web-Browsing, Softwareentwicklung und Frontend-Codierung und integriert sich mit Code-Agenten wie Claude Code und Roo Code. Es nutzt hybrides Reasoning für komplexe und alltägliche Szenarien.",
"zai-org/GLM-4.5V.description": "GLM-4.5V ist Zhipu AIs neuestes VLM, basierend auf dem GLM-4.5-Air-Textmodell (106B gesamt, 12B aktiv) mit MoE-Architektur für starke Leistung bei geringeren Kosten. Es folgt dem GLM-4.1V-Thinking-Ansatz und fügt 3D-RoPE zur Verbesserung des 3D-Räumlichkeitsdenkens hinzu. Optimiert durch Pretraining, SFT und RL, verarbeitet es Bilder, Videos und lange Dokumente und belegt Spitzenplätze unter offenen Modellen in 41 öffentlichen multimodalen Benchmarks. Ein Thinking-Modus-Schalter ermöglicht die Balance zwischen Geschwindigkeit und Tiefe.",
"zai-org/GLM-4.6.description": "Im Vergleich zu GLM-4.5 erweitert GLM-4.6 den Kontext von 128K auf 200K für komplexere Agentenaufgaben. Es erzielt höhere Werte in Code-Benchmarks und zeigt stärkere reale Leistung in Apps wie Claude Code, Cline, Roo Code und Kilo Code einschließlich besserer Frontend-Seitengenerierung. Reasoning wurde verbessert und Toolnutzung während des Denkens unterstützt, was die Gesamtleistung stärkt. Es integriert sich besser in Agentenframeworks, verbessert Tool-/Suchagenten und bietet einen menschenfreundlicheren Schreibstil und natürlichere Rollenspiele.",
"zai-org/GLM-4.6V.description": "GLM-4.6V erreicht SOTA-Genauigkeit im visuellen Verständnis für seine Parametergröße und ist das erste Modell, das nativ Funktionaufruf-Fähigkeiten in die Architektur des visuellen Modells integriert, die Lücke zwischen visueller Wahrnehmung und ausführbaren Aktionen“ schließt und eine einheitliche technische Grundlage für multimodale Agenten in realen Geschäftsszenarien bietet. Das visuelle Kontextfenster wird auf 128k erweitert und unterstützt die Verarbeitung langer Videostreams und hochauflösender Multi-Bild-Analysen.",
"zai-org/GLM-4.6V.description": "GLM-4.6V erreicht SOTA-Genauigkeit bei visueller Wahrnehmung für seine Parametergröße und ist das erste Modell, das Funktion-Call-Fähigkeiten nativ in die Architektur des Vision-Modells integriert, wodurch die Lücke zwischen 'visueller Wahrnehmung' und 'ausführbaren Aktionen' geschlossen wird. Es bietet eine einheitliche technische Grundlage für multimodale Agenten in realen Geschäftsszenarien. Das visuelle Kontextfenster wird auf 128k erweitert und unterstützt die Verarbeitung langer Videostreams sowie die Analyse hochauflösender Multi-Bilder.",
"zai/glm-4.5-air.description": "GLM-4.5 und GLM-4.5-Air sind unsere neuesten Flaggschiffe für Agentenanwendungen, beide mit MoE. GLM-4.5 hat 355B gesamt und 32B aktiv pro Forward-Pass; GLM-4.5-Air ist schlanker mit 106B gesamt und 12B aktiv.",
"zai/glm-4.5.description": "Die GLM-4.5-Serie ist für Agenten konzipiert. Das Flaggschiff GLM-4.5 kombiniert Reasoning-, Coding- und Agentenfähigkeiten mit 355B Gesamtparametern (32B aktiv) und bietet zwei Betriebsmodi als hybrides Reasoning-System.",
"zai/glm-4.5v.description": "GLM-4.5V baut auf GLM-4.5-Air auf, übernimmt bewährte GLM-4.1V-Thinking-Techniken und skaliert mit einer starken 106B-Parameter-MoE-Architektur.",
+1 -1
View File
@@ -1,6 +1,7 @@
{
"arguments.moreParams": "{{count}} Parameter insgesamt",
"arguments.title": "Argumente",
"builtins.lobe-activator.apiName.activateTools": "Werkzeuge aktivieren",
"builtins.lobe-agent-builder.apiName.getAvailableModels": "Verfügbare Modelle abrufen",
"builtins.lobe-agent-builder.apiName.getAvailableTools": "Verfügbare Skills abrufen",
"builtins.lobe-agent-builder.apiName.getConfig": "Konfiguration abrufen",
@@ -209,7 +210,6 @@
"builtins.lobe-skills.apiName.runCommand": "Befehl ausführen",
"builtins.lobe-skills.apiName.searchSkill": "Fähigkeiten suchen",
"builtins.lobe-skills.title": "Fähigkeiten",
"builtins.lobe-tools.apiName.activateTools": "Werkzeuge aktivieren",
"builtins.lobe-topic-reference.apiName.getTopicContext": "Themenkontext abrufen",
"builtins.lobe-topic-reference.title": "Themenreferenz",
"builtins.lobe-user-memory.apiName.addContextMemory": "Kontextgedächtnis hinzufügen",
+6 -1
View File
@@ -8,6 +8,7 @@
"azure.description": "Azure bietet fortschrittliche KI-Modelle, darunter die GPT-3.5- und GPT-4-Serien, für vielfältige Datentypen und komplexe Aufgaben mit Fokus auf sichere, zuverlässige und nachhaltige KI.",
"azureai.description": "Azure stellt fortschrittliche KI-Modelle wie GPT-3.5 und GPT-4 für verschiedenste Datentypen und komplexe Aufgaben bereit mit Fokus auf Sicherheit, Zuverlässigkeit und Nachhaltigkeit.",
"baichuan.description": "Baichuan AI konzentriert sich auf Foundation-Modelle mit starker Leistung im chinesischen Sprachverständnis, Langkontextverarbeitung und kreativer Generierung. Die Modelle (Baichuan 4, Baichuan 3 Turbo, Baichuan 3 Turbo 128k) sind für verschiedene Szenarien optimiert und bieten hohen Mehrwert.",
"bailiancodingplan.description": "Der Aliyun Bailian Coding Plan ist ein spezialisierter KI-Coding-Dienst, der über einen dedizierten Endpunkt Zugriff auf coding-optimierte Modelle wie Qwen, GLM, Kimi und MiniMax bietet.",
"bedrock.description": "Amazon Bedrock stellt Unternehmen fortschrittliche Sprach- und Bildmodelle zur Verfügung, darunter Anthropic Claude und Meta Llama 3.1 von leichten bis leistungsstarken Optionen für Text-, Chat- und Bildaufgaben.",
"bfl.description": "Ein führendes KI-Forschungslabor an der Spitze der visuellen Infrastruktur von morgen.",
"cerebras.description": "Cerebras ist eine Inferenzplattform auf Basis des CS-3-Systems, die auf extrem niedrige Latenz und hohen Durchsatz für Echtzeitanwendungen wie Codegenerierung und Agentenaufgaben ausgelegt ist.",
@@ -21,6 +22,7 @@
"giteeai.description": "Gitee AI Serverless APIs bieten sofort einsatzbereite LLM-Inferenzdienste für Entwickler.",
"github.description": "Mit GitHub Models können Entwickler als KI-Ingenieure mit branchenführenden Modellen arbeiten.",
"githubcopilot.description": "Greifen Sie mit Ihrem GitHub Copilot-Abonnement auf die Modelle Claude, GPT und Gemini zu.",
"glmcodingplan.description": "Der GLM Coding Plan bietet Zugriff auf Zhipu AI-Modelle, darunter GLM-5 und GLM-4.7, für Coding-Aufgaben im Rahmen eines Festpreis-Abonnements.",
"google.description": "Die Gemini-Familie von Google ist die fortschrittlichste Allzweck-KI von Google DeepMind für multimodale Anwendungen in Text, Code, Bildern, Audio und Video. Sie skaliert effizient von Rechenzentren bis zu Mobilgeräten.",
"groq.description": "Groqs LPU-Inferenz-Engine liefert herausragende Benchmark-Leistung mit außergewöhnlicher Geschwindigkeit und Effizienz ideal für latenzarme, cloudbasierte LLM-Inferenz.",
"higress.description": "Higress ist ein cloud-natives API-Gateway, das bei Alibaba entwickelt wurde, um Tengine-Neuladeprobleme bei langlebigen Verbindungen und Lücken im gRPC/Dubbo-Load-Balancing zu beheben.",
@@ -29,10 +31,12 @@
"infiniai.description": "Bietet App-Entwicklern leistungsstarke, benutzerfreundliche und sichere LLM-Dienste über den gesamten Workflow von der Modellentwicklung bis zur produktiven Bereitstellung.",
"internlm.description": "Eine Open-Source-Organisation für Forschung und Tools rund um große Modelle mit einer effizienten, benutzerfreundlichen Plattform für den Zugang zu modernsten Modellen und Algorithmen.",
"jina.description": "Jina AI wurde 2020 gegründet und ist ein führendes Unternehmen im Bereich Such-KI. Der Such-Stack umfasst Vektormodelle, Reranker und kleine Sprachmodelle für zuverlässige, hochwertige generative und multimodale Suchanwendungen.",
"kimicodingplan.description": "Kimi Code von Moonshot AI bietet Zugriff auf Kimi-Modelle, darunter K2.5, für Coding-Aufgaben.",
"lmstudio.description": "LM Studio ist eine Desktop-App zur Entwicklung und zum Experimentieren mit LLMs auf dem eigenen Computer.",
"lobehub.description": "LobeHub Cloud verwendet offizielle APIs, um auf KI-Modelle zuzugreifen, und misst die Nutzung mit Credits, die an Modell-Token gebunden sind.",
"lobehub.description": "LobeHub Cloud verwendet offizielle APIs, um auf KI-Modelle zuzugreifen, und misst die Nutzung mit Credits, die an Modell-Tokens gebunden sind.",
"longcat.description": "LongCat ist eine Reihe von generativen KI-Großmodellen, die unabhängig von Meituan entwickelt wurden. Sie sind darauf ausgelegt, die Produktivität innerhalb des Unternehmens zu steigern und innovative Anwendungen durch eine effiziente Rechenarchitektur und starke multimodale Fähigkeiten zu ermöglichen.",
"minimax.description": "MiniMax wurde 2021 gegründet und entwickelt allgemeine KI mit multimodalen Foundation-Modellen, darunter Textmodelle mit Billionen Parametern, Sprach- und Bildmodelle sowie Apps wie Hailuo AI.",
"minimaxcodingplan.description": "Der MiniMax Token Plan bietet Zugriff auf MiniMax-Modelle, darunter M2.7, für Coding-Aufgaben im Rahmen eines Festpreis-Abonnements.",
"mistral.description": "Mistral bietet fortschrittliche allgemeine, spezialisierte und Forschungsmodelle für komplexes Denken, mehrsprachige Aufgaben und Codegenerierung inklusive Funktionsaufrufen für individuelle Integrationen.",
"modelscope.description": "ModelScope ist die Model-as-a-Service-Plattform von Alibaba Cloud mit einer breiten Auswahl an KI-Modellen und Inferenzdiensten.",
"moonshot.description": "Moonshot von Moonshot AI (Beijing Moonshot Technology) bietet mehrere NLP-Modelle für Anwendungsfälle wie Content-Erstellung, Forschung, Empfehlungen und medizinische Analysen mit starker Langkontext- und komplexer Generierungsunterstützung.",
@@ -65,6 +69,7 @@
"vertexai.description": "Die Gemini-Familie von Google ist die fortschrittlichste Allzweck-KI von Google DeepMind für multimodale Anwendungen in Text, Code, Bildern, Audio und Video skalierbar von Rechenzentren bis zu Mobilgeräten.",
"vllm.description": "vLLM ist eine schnelle, benutzerfreundliche Bibliothek für LLM-Inferenz und -Bereitstellung.",
"volcengine.description": "Die Modellserviceplattform von ByteDance bietet sicheren, funktionsreichen und kostengünstigen Modellzugang sowie End-to-End-Tools für Daten, Feintuning, Inferenz und Bewertung.",
"volcenginecodingplan.description": "Der Volcengine Coding Plan von ByteDance bietet Zugriff auf mehrere Coding-Modelle, darunter Doubao-Seed-Code, GLM-4.7, DeepSeek-V3.2 und Kimi-K2.5, im Rahmen eines Festpreis-Abonnements.",
"wenxin.description": "Eine All-in-One-Plattform für Unternehmen zur Entwicklung von Foundation-Modellen und KI-nativen Anwendungen mit End-to-End-Tools für generative KI-Workflows.",
"xai.description": "xAI entwickelt KI zur Beschleunigung wissenschaftlicher Entdeckungen mit dem Ziel, das Verständnis des Universums durch die Menschheit zu vertiefen.",
"xiaomimimo.description": "Xiaomi MiMo bietet einen Konversationsmodell-Service mit einer OpenAI-kompatiblen API. Das Modell mimo-v2-flash unterstützt tiefgreifendes Schlussfolgern, Streaming-Ausgaben, Funktionsaufrufe, ein Kontextfenster von 256K sowie eine maximale Ausgabe von 128K.",
+65
View File
@@ -193,6 +193,70 @@
"analytics.title": "Analytik",
"checking": "Überprüfung läuft...",
"checkingPermissions": "Berechtigungen werden überprüft...",
"creds.actions.delete": "Löschen",
"creds.actions.deleteConfirm.cancel": "Abbrechen",
"creds.actions.deleteConfirm.content": "Diese Berechtigung wird dauerhaft gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.",
"creds.actions.deleteConfirm.ok": "Löschen",
"creds.actions.deleteConfirm.title": "Berechtigung löschen?",
"creds.actions.edit": "Bearbeiten",
"creds.actions.view": "Ansehen",
"creds.create": "Neue Berechtigung",
"creds.createModal.fillForm": "Details ausfüllen",
"creds.createModal.selectType": "Typ auswählen",
"creds.createModal.title": "Berechtigung erstellen",
"creds.edit.title": "Berechtigung bearbeiten",
"creds.empty": "Noch keine Berechtigungen konfiguriert",
"creds.file.authRequired": "Bitte melden Sie sich zuerst im Market an",
"creds.file.uploadFailed": "Datei-Upload fehlgeschlagen",
"creds.file.uploadSuccess": "Datei erfolgreich hochgeladen",
"creds.file.uploading": "Hochladen...",
"creds.form.addPair": "Schlüssel-Wert-Paar hinzufügen",
"creds.form.back": "Zurück",
"creds.form.cancel": "Abbrechen",
"creds.form.connectionRequired": "Bitte wählen Sie eine OAuth-Verbindung aus",
"creds.form.description": "Beschreibung",
"creds.form.descriptionPlaceholder": "Optionale Beschreibung für diese Berechtigung",
"creds.form.file": "Berechtigungsdatei",
"creds.form.fileRequired": "Bitte laden Sie eine Datei hoch",
"creds.form.key": "Bezeichner",
"creds.form.keyPattern": "Bezeichner darf nur Buchstaben, Zahlen, Unterstriche und Bindestriche enthalten",
"creds.form.keyRequired": "Bezeichner ist erforderlich",
"creds.form.name": "Anzeigename",
"creds.form.nameRequired": "Anzeigename ist erforderlich",
"creds.form.save": "Speichern",
"creds.form.selectConnection": "OAuth-Verbindung auswählen",
"creds.form.selectConnectionPlaceholder": "Wählen Sie ein verbundenes Konto",
"creds.form.selectedFile": "Ausgewählte Datei",
"creds.form.submit": "Erstellen",
"creds.form.uploadDesc": "Unterstützt JSON-, PEM- und andere Berechtigungsdateiformate",
"creds.form.uploadHint": "Klicken oder Datei ziehen, um hochzuladen",
"creds.form.valuePlaceholder": "Wert eingeben",
"creds.form.values": "Schlüssel-Wert-Paare",
"creds.oauth.noConnections": "Keine OAuth-Verbindungen verfügbar. Bitte verbinden Sie zuerst ein Konto.",
"creds.signIn": "Im Market anmelden",
"creds.signInRequired": "Bitte melden Sie sich im Market an, um Ihre Berechtigungen zu verwalten",
"creds.table.actions": "Aktionen",
"creds.table.key": "Bezeichner",
"creds.table.lastUsed": "Zuletzt verwendet",
"creds.table.name": "Name",
"creds.table.neverUsed": "Nie",
"creds.table.preview": "Vorschau",
"creds.table.type": "Typ",
"creds.typeDesc.file": "Berechtigungsdateien wie Servicekonten oder Zertifikate hochladen",
"creds.typeDesc.kv-env": "API-Schlüssel und Tokens als Umgebungsvariablen speichern",
"creds.typeDesc.kv-header": "Autorisierungswerte als HTTP-Header speichern",
"creds.typeDesc.oauth": "Mit einer bestehenden OAuth-Verbindung verknüpfen",
"creds.types.all": "Alle",
"creds.types.file": "Datei",
"creds.types.kv-env": "Umgebung",
"creds.types.kv-header": "Header",
"creds.types.oauth": "OAuth",
"creds.view.error": "Berechtigung konnte nicht geladen werden",
"creds.view.noValues": "Keine Werte",
"creds.view.oauthNote": "OAuth-Berechtigungen werden vom verbundenen Dienst verwaltet.",
"creds.view.title": "Berechtigung ansehen: {{name}}",
"creds.view.values": "Berechtigungswerte",
"creds.view.warning": "Diese Werte sind sensibel. Teilen Sie sie nicht mit anderen.",
"danger.clear.action": "Jetzt löschen",
"danger.clear.confirm": "Alle Chatdaten löschen? Dies kann nicht rückgängig gemacht werden.",
"danger.clear.desc": "Alle Daten löschen, einschließlich Agenten, Dateien, Nachrichten und Fähigkeiten. Dein Konto wird NICHT gelöscht.",
@@ -731,6 +795,7 @@
"tab.appearance": "Erscheinungsbild",
"tab.chatAppearance": "Chat-Darstellung",
"tab.common": "Darstellung",
"tab.creds": "Berechtigungen",
"tab.experiment": "Experiment",
"tab.hotkey": "Tastenkombinationen",
"tab.image": "Bildgenerierungsdienst",
+5
View File
@@ -199,6 +199,8 @@
"plans.btn.paymentDesc": "Unterstützt Kreditkarte / Alipay / WeChat Pay",
"plans.btn.paymentDescForZarinpal": "Unterstützt Kreditkarte",
"plans.btn.soon": "Demnächst verfügbar",
"plans.cancelDowngrade": "Geplante Herabstufung abbrechen",
"plans.cancelDowngradeSuccess": "Geplante Herabstufung wurde abgebrochen",
"plans.changePlan": "Plan auswählen",
"plans.cloud.history": "Unbegrenzter Gesprächsverlauf",
"plans.cloud.sync": "Globale Cloud-Synchronisierung",
@@ -215,6 +217,7 @@
"plans.current": "Aktueller Plan",
"plans.downgradePlan": "Ziel-Down-Grade-Plan",
"plans.downgradeTip": "Sie haben bereits einen Planwechsel vorgenommen. Weitere Änderungen sind erst nach Abschluss möglich",
"plans.downgradeWillCancel": "Diese Aktion wird Ihre geplante Tarifherabstufung abbrechen",
"plans.embeddingStorage.embeddings": "Einträge",
"plans.embeddingStorage.title": "Vektorspeicher",
"plans.embeddingStorage.tooltip": "Eine Dokumentenseite (10001500 Zeichen) erzeugt ca. 1 Vektoreintrag. (Schätzung basierend auf OpenAI Embeddings, modellabhängig)",
@@ -253,6 +256,7 @@
"plans.payonce.ok": "Auswahl bestätigen",
"plans.payonce.popconfirm": "Nach einer Einmalzahlung können Sie den Plan oder Abrechnungszeitraum erst nach Ablauf ändern. Bitte bestätigen Sie Ihre Auswahl.",
"plans.payonce.tooltip": "Bei Einmalzahlung ist ein Wechsel erst nach Ablauf des Abonnements möglich",
"plans.pendingDowngrade": "Ausstehende Herabstufung",
"plans.plan.enterprise.contactSales": "Vertrieb kontaktieren",
"plans.plan.enterprise.title": "Enterprise",
"plans.plan.free.desc": "Für Erstnutzer",
@@ -366,6 +370,7 @@
"summary.title": "Abrechnungsübersicht",
"summary.usageThisMonth": "Nutzung in diesem Monat anzeigen.",
"summary.viewBillingHistory": "Zahlungsverlauf anzeigen",
"switchDowngradeTarget": "Ziel der Herabstufung ändern",
"switchPlan": "Plan wechseln",
"switchToMonthly.desc": "Nach dem Wechsel wird die monatliche Abrechnung nach Ablauf des aktuellen Jahresplans aktiv.",
"switchToMonthly.title": "Zu monatlicher Abrechnung wechseln",
+3 -1
View File
@@ -86,5 +86,7 @@
"channel.wechatQrScaned": "QR code scanned. Please confirm the login in WeChat.",
"channel.wechatQrWait": "Open WeChat and scan the QR code to connect.",
"channel.wechatScanTitle": "Connect WeChat Bot",
"channel.wechatScanToConnect": "Scan QR Code to Connect"
"channel.wechatScanToConnect": "Scan QR Code to Connect",
"channel.wechatTip1": "Please update WeChat to the latest version, and it is recommended to restart WeChat.",
"channel.wechatTip2": "The WeChat ClawBot plugin is currently in gradual rollout. You can check Settings => Plugins to confirm whether you have access."
}
+1 -1
View File
@@ -230,7 +230,7 @@
"tab.profile": "My Account",
"tab.security": "Security",
"tab.stats": "Statistics",
"tab.usage": "Usage Statistics",
"tab.usage": "Usage",
"usage.activeModels.modelTable": "Model List",
"usage.activeModels.models": "Active Models",
"usage.activeModels.providerTable": "Provider List",
+8 -6
View File
@@ -97,7 +97,7 @@
"cmdk.aiModeEmptyState": "Type your question above to start chatting with AI",
"cmdk.aiModeHint": "Press Enter to ask",
"cmdk.aiModePlaceholder": "Ask AI anything...",
"cmdk.aiPainting": "AI Art",
"cmdk.aiPainting": "AI Image",
"cmdk.askAI": "Ask Agent",
"cmdk.askAIHeading": "Use the following features for {{query}}",
"cmdk.askAIHeadingEmpty": "Choose an AI feature",
@@ -113,7 +113,7 @@
"cmdk.context.group": "Group",
"cmdk.context.memory": "Memory",
"cmdk.context.page": "Page",
"cmdk.context.painting": "Painting",
"cmdk.context.painting": "Image",
"cmdk.context.resource": "Resource",
"cmdk.context.settings": "Settings",
"cmdk.discover": "Discover",
@@ -156,7 +156,7 @@
"cmdk.noResults": "No Results found",
"cmdk.openSettings": "Open Settings",
"cmdk.pages": "Pages",
"cmdk.painting": "Painting",
"cmdk.painting": "Image",
"cmdk.resource": "Resources",
"cmdk.search.agent": "Agent",
"cmdk.search.agents": "Agents",
@@ -397,7 +397,6 @@
"sync.status.unconnected": "Connection Failed",
"sync.title": "Sync Status",
"sync.unconnected.tip": "Signaling server connection failed, and peer-to-peer communication channel cannot be established. Please check the network and try again.",
"tab.aiImage": "Artwork",
"tab.audio": "Audio",
"tab.chat": "Chat",
"tab.community": "Community",
@@ -405,6 +404,7 @@
"tab.eval": "Eval Lab",
"tab.files": "Files",
"tab.home": "Home",
"tab.image": "Image",
"tab.knowledgeBase": "Library",
"tab.marketplace": "Marketplace",
"tab.me": "Me",
@@ -429,9 +429,10 @@
"upgradeVersion.newVersion": "Update available: {{version}}",
"upgradeVersion.serverVersion": "Server: {{version}}",
"userPanel.anonymousNickName": "Anonymous User",
"userPanel.billing": "Billing Management",
"userPanel.billing": "Billing",
"userPanel.cloud": "Launch {{name}}",
"userPanel.community": "Community",
"userPanel.credits": "Credits",
"userPanel.data": "Data Storage",
"userPanel.defaultNickname": "Community User",
"userPanel.discord": "Discord",
@@ -443,6 +444,7 @@
"userPanel.plans": "Subscription Plans",
"userPanel.profile": "Account",
"userPanel.setting": "Settings",
"userPanel.usages": "Usage Statistics",
"userPanel.upgradePlan": "Upgrade Plan",
"userPanel.usages": "Usage",
"version": "Version"
}
+9
View File
@@ -1,4 +1,13 @@
{
"gateway.description": "Description",
"gateway.descriptionPlaceholder": "Optional",
"gateway.deviceName": "Device Name",
"gateway.deviceNamePlaceholder": "Enter device name",
"gateway.enableConnection": "Connect to Gateway",
"gateway.statusConnected": "Connected to Gateway",
"gateway.statusConnecting": "Connecting to Gateway...",
"gateway.statusDisconnected": "Not connected to Gateway",
"gateway.title": "Device Gateway",
"navigation.chat": "Chat",
"navigation.discover": "Discover",
"navigation.discoverAssistants": "Discover Assistants",
+2 -2
View File
@@ -4,7 +4,7 @@
"config.aspectRatio.unlock": "Unlock Aspect Ratio",
"config.cfg.label": "Guidance Intensity",
"config.header.desc": "Brief description, create instantly",
"config.header.title": "Painting",
"config.header.title": "Image",
"config.height.label": "Height",
"config.imageNum.label": "Number of Images",
"config.imageUrl.label": "Reference Image",
@@ -58,6 +58,6 @@
"topic.deleteConfirm": "Delete Generation Topic",
"topic.deleteConfirmDesc": "You are about to delete this generation topic. This action cannot be undone, please proceed with caution.",
"topic.empty": "No generation topics",
"topic.title": "Painting Theme",
"topic.title": "Image Topic",
"topic.untitled": "Default Topic"
}
+2
View File
@@ -231,6 +231,8 @@
"providerModels.item.modelConfig.extendParams.options.imageResolution.hint": "For Gemini 3 image generation models; controls resolution of generated images.",
"providerModels.item.modelConfig.extendParams.options.imageResolution2.hint": "For Gemini 3.1 Flash Image models; controls resolution of generated images (supports 512px).",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken.hint": "For Claude, Qwen3 and similar; controls token budget for reasoning.",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken32k.hint": "For GLM-5 and GLM-4.7; controls token budget for reasoning (max 32k).",
"providerModels.item.modelConfig.extendParams.options.reasoningBudgetToken80k.hint": "For Qwen3 series; controls token budget for reasoning (max 80k).",
"providerModels.item.modelConfig.extendParams.options.reasoningEffort.hint": "For OpenAI and other reasoning-capable models; controls reasoning effort.",
"providerModels.item.modelConfig.extendParams.options.textVerbosity.hint": "For GPT-5+ series; controls output verbosity.",
"providerModels.item.modelConfig.extendParams.options.thinking.hint": "For some Doubao models; allow model to decide whether to think deeply.",
+14 -6
View File
@@ -53,7 +53,14 @@
"FLUX.1-Kontext-dev.description": "FLUX.1-Kontext-dev is a multimodal image generation and editing model from Black Forest Labs based on a Rectified Flow Transformer architecture with 12B parameters. It focuses on generating, reconstructing, enhancing, or editing images under given context conditions. It combines the controllable generation strengths of diffusion models with Transformer context modeling, supporting high-quality outputs for tasks like inpainting, outpainting, and visual scene reconstruction.",
"FLUX.1-Kontext-pro.description": "FLUX.1 Kontext [pro]",
"FLUX.1-dev.description": "FLUX.1-dev is an open-source multimodal language model (MLLM) from Black Forest Labs, optimized for image-text tasks and combining image/text understanding and generation. Built on advanced LLMs (such as Mistral-7B), it uses a carefully designed vision encoder and multi-stage instruction tuning to enable multimodal coordination and complex task reasoning.",
"GLM-4.5-Air.description": "GLM-4.5-Air: Lightweight version for fast responses.",
"GLM-4.5.description": "GLM-4.5: High-performance model for reasoning, coding, and agent tasks.",
"GLM-4.6.description": "GLM-4.6: Previous generation model.",
"GLM-4.7.description": "GLM-4.7 is Zhipu's latest flagship model, enhanced for Agentic Coding scenarios with improved coding capabilities, long-term task planning, and tool collaboration.",
"GLM-5-Turbo.description": "GLM-5-Turbo: Optimized version of GLM-5 with faster inference for coding tasks.",
"GLM-5.description": "GLM-5 is Zhipu's next-generation flagship foundation model, purpose-built for Agentic Engineering. It delivers reliable productivity in complex systems engineering and long-horizon agentic tasks. In coding and agent capabilities, GLM-5 achieves state-of-the-art performance among open-source models.",
"Gryphe/MythoMax-L2-13b.description": "MythoMax-L2 (13B) is an innovative model for diverse domains and complex tasks.",
"HY-Image-V3.0.description": "Powerful original-image feature extraction and detail preservation capabilities, delivering richer visual texture and producing high-accuracy, well-composed, production-grade visuals.",
"HelloMeme.description": "HelloMeme is an AI tool that generates memes, GIFs, or short videos from the images or motions you provide. It requires no drawing or coding skills—just a reference image—to produce fun, attractive, and stylistically consistent content.",
"HiDream-E1-Full.description": "HiDream-E1-Full is an open-source multimodal image editing model from HiDream.ai, based on an advanced Diffusion Transformer architecture and strong language understanding (built-in LLaMA 3.1-8B-Instruct). It supports natural-language-driven image generation, style transfer, local edits, and repainting, with excellent image-text understanding and execution.",
"HiDream-I1-Full.description": "HiDream-I1 is a new open-source base image generation model released by HiDream. With 17B parameters (Flux has 12B), it can deliver industry-leading image quality in seconds.",
@@ -84,11 +91,11 @@
"MiniMax-M2.1-highspeed.description": "Powerful multilingual programming capabilities with faster and more efficient inference.",
"MiniMax-M2.1.description": "MiniMax-M2.1 is a flagship open-source large model from MiniMax, focusing on solving complex real-world tasks. Its core strengths are multi-language programming capabilities and the ability to solve complex tasks as an Agent.",
"MiniMax-M2.5-Lightning.description": "M2.5 Lightning: Same performance, faster and more agile (approx. 100 tps).",
"MiniMax-M2.5-highspeed.description": "Same performance as M2.5 with significantly faster inference.",
"MiniMax-M2.5-highspeed.description": "MiniMax M2.5 Highspeed: Same performance as M2.5 with faster inference.",
"MiniMax-M2.5.description": "MiniMax-M2.5 is a flagship open-source large model from MiniMax, focusing on solving complex real-world tasks. Its core strengths are multi-language programming capabilities and the ability to solve complex tasks as an Agent.",
"MiniMax-M2.7-highspeed.description": "Same performance as M2.7 with significantly faster inference (~100 tps).",
"MiniMax-M2.7.description": "First self-evolving model with top-tier coding and agentic performance (~60 tps).",
"MiniMax-M2.description": "Built specifically for efficient coding and Agent workflows",
"MiniMax-M2.7-highspeed.description": "MiniMax M2.7 Highspeed: Same performance as M2.7 with significantly faster inference.",
"MiniMax-M2.7.description": "MiniMax M2.7: Beginning the journey of recursive self-improvement, top real-world engineering capabilities.",
"MiniMax-M2.description": "MiniMax M2: Previous generation model.",
"MiniMax-Text-01.description": "MiniMax-01 introduces large-scale linear attention beyond classic Transformers, with 456B parameters and 45.9B activated per pass. It achieves top-tier performance and supports up to 4M tokens of context (32× GPT-4o, 20× Claude-3.5-Sonnet).",
"MiniMaxAI/MiniMax-M1-80k.description": "MiniMax-M1 is an open-weights large-scale hybrid-attention reasoning model with 456B total parameters and ~45.9B active per token. It natively supports 1M context and uses Flash Attention to cut FLOPs by 75% on 100K-token generation vs DeepSeek R1. With an MoE architecture plus CISPO and hybrid-attention RL training, it achieves leading performance on long-input reasoning and real software engineering tasks.",
"MiniMaxAI/MiniMax-M2.description": "MiniMax-M2 redefines agent efficiency. It is a compact, fast, cost-effective MoE model with 230B total and 10B active parameters, built for top-tier coding and agent tasks while retaining strong general intelligence. With only 10B active parameters, it rivals much larger models, making it ideal for high-efficiency applications.",
@@ -417,7 +424,7 @@
"deepseek-v3.2-exp.description": "deepseek-v3.2-exp introduces sparse attention to improve training and inference efficiency on long text, at a lower price than deepseek-v3.1.",
"deepseek-v3.2-speciale.description": "On highly complex tasks, the Speciale model significantly outperforms the standard version, but it consumes considerably more tokens and incurs higher costs. Currently, DeepSeek-V3.2-Speciale is intended for research use only, does not support tool calls, and has not been specifically optimized for everyday conversation or writing tasks.",
"deepseek-v3.2-think.description": "DeepSeek V3.2 Think is a full deep-thinking model with stronger long-chain reasoning.",
"deepseek-v3.2.description": "DeepSeek-V3.2 is the first hybrid reasoning model from DeepSeek that integrates thinking into tool usage. It uses efficient architecture to save computation, large-scale reinforcement learning to enhance capabilities, and large-scale synthetic task data to strengthen generalization. The combination of these three achieves performance comparable to GPT-5-High, with significantly reduced output length, notably decreasing computational overhead and user wait times.",
"deepseek-v3.2.description": "DeepSeek-V3.2 is DeepSeek's latest coding model with strong reasoning capabilities.",
"deepseek-v3.description": "DeepSeek-V3 is a powerful MoE model with 671B total parameters and 37B active per token.",
"deepseek-vl2-small.description": "DeepSeek VL2 Small is a lightweight multimodal version for resource-constrained and high-concurrency use.",
"deepseek-vl2.description": "DeepSeek VL2 is a multimodal model for image-text understanding and fine-grained visual QA.",
@@ -798,7 +805,7 @@
"kimi-k2-thinking-turbo.description": "High-speed K2 long-thinking variant with 256k context, strong deep reasoning, and 60100 tokens/sec output.",
"kimi-k2-thinking.description": "kimi-k2-thinking is a Moonshot AI thinking model with general agentic and reasoning abilities. It excels at deep reasoning and can solve hard problems via multi-step tool use.",
"kimi-k2-turbo-preview.description": "kimi-k2 is an MoE foundation model with strong coding and agent capabilities (1T total params, 32B active), outperforming other mainstream open models across reasoning, programming, math, and agent benchmarks.",
"kimi-k2.5.description": "Kimi K2.5 is the most capable Kimi model, delivering open-source SOTA in agent tasks, coding, and vision understanding. It supports multimodal inputs and both thinking and non-thinking modes.",
"kimi-k2.5.description": "Kimi K2.5 is Kimi's most versatile model to date, featuring a native multimodal architecture that supports both vision and text inputs, 'thinking' and 'non-thinking' modes, and both conversational and agent tasks.",
"kimi-k2.description": "Kimi-K2 is a MoE base model from Moonshot AI with strong coding and agent capabilities, totaling 1T parameters with 32B active. On benchmarks for general reasoning, coding, math, and agent tasks, it outperforms other mainstream open models.",
"kimi-k2:1t.description": "Kimi K2 is a large MoE LLM from Moonshot AI with 1T total parameters and 32B active per forward pass. It is optimized for agent capabilities including advanced tool use, reasoning, and code synthesis.",
"kuaishou/kat-coder-pro-v1.description": "KAT-Coder-Pro-V1 (limited-time free) focuses on code understanding and automation for efficient coding agents.",
@@ -1163,6 +1170,7 @@
"qwen3-coder-next.description": "Nextgen Qwen coder optimized for complex multi-file code generation, debugging, and highthroughput agent workflows. Designed for strong tool integration and improved reasoning performance.",
"qwen3-coder-plus.description": "Qwen code model. The latest Qwen3-Coder series is based on Qwen3 and delivers strong coding-agent abilities, tool use, and environment interaction for autonomous programming, with excellent code performance and solid general capability.",
"qwen3-coder:480b.description": "Alibaba's high-performance long-context model for agent and coding tasks.",
"qwen3-max-2026-01-23.description": "Qwen3 Max: Best-performing Qwen model for complex, multi-step coding tasks with thinking support.",
"qwen3-max-preview.description": "Best-performing Qwen model for complex, multi-step tasks. The preview supports thinking.",
"qwen3-max.description": "Qwen3 Max models deliver large gains over the 2.5 series in general ability, Chinese/English understanding, complex instruction following, subjective open tasks, multilingual ability, and tool use, with fewer hallucinations. The latest qwen3-max improves agentic programming and tool use over qwen3-max-preview. This release reaches field SOTA and targets more complex agent needs.",
"qwen3-next-80b-a3b-instruct.description": "Next-gen Qwen3 non-thinking open-source model. Compared to the prior version (Qwen3-235B-A22B-Instruct-2507), it has better Chinese understanding, stronger logical reasoning, and improved text generation.",

Some files were not shown because too many files have changed in this diff Show More