mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-14 03:30:19 +00:00
Compare commits
124 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d38d59e8e | |||
| 41c71655b6 | |||
| 26da6b9ad4 | |||
| 1d4fb21885 | |||
| 38c92fa04a | |||
| 555a375e67 | |||
| 6989e8f9e6 | |||
| e4d1d1fc17 | |||
| 026c79a4c2 | |||
| 1e2782ece4 | |||
| b5ddac56dc | |||
| ad0da3753e | |||
| e6905fe0fd | |||
| a9d2110565 | |||
| e4d5f69b27 | |||
| a372acd50d | |||
| 0af5e51477 | |||
| 40f0557158 | |||
| 62f06540ba | |||
| 43b064f803 | |||
| 8e8a463a05 | |||
| decc25554e | |||
| 1c8ec2681c | |||
| 0a32fbc737 | |||
| 7fc41a9677 | |||
| 22c880763d | |||
| d324736edf | |||
| 608498a950 | |||
| 5e1a35f259 | |||
| 6b010c8380 | |||
| ead5631bab | |||
| ddd5c20836 | |||
| c51835193f | |||
| 0c375e4428 | |||
| 58cda8a645 | |||
| 65ba4ad435 | |||
| 41ffd1e0d3 | |||
| 02767bac55 | |||
| be5d61d40a | |||
| 282b20c454 | |||
| cc506c036d | |||
| 5fca91a488 | |||
| c3530ad221 | |||
| 8b8b0f0579 | |||
| 958bf52978 | |||
| 480d4b2b4e | |||
| 4d00c22e7f | |||
| f30d9da5a9 | |||
| 831b4ee5ca | |||
| c744eab116 | |||
| 7697399da8 | |||
| 05a9eae504 | |||
| cc1e0d29d3 | |||
| 0e6eba61a9 | |||
| 3e8016b502 | |||
| 970733aaeb | |||
| c72b1ee698 | |||
| 7bf923d762 | |||
| 10300ba0e1 | |||
| 431abf36d6 | |||
| ce516fff9d | |||
| 9e231835b2 | |||
| 79b84a68ec | |||
| 56e811f5bd | |||
| 5fb795b092 | |||
| fbe71e76db | |||
| d83f0a0f2f | |||
| fe65741a32 | |||
| b5e4cd0805 | |||
| f565ca9450 | |||
| e6d49fdb76 | |||
| 47c524a388 | |||
| cb4412421f | |||
| 78b3dbed03 | |||
| 95375cec79 | |||
| aa3c7e585b | |||
| 11e6619a3c | |||
| 41719dfd29 | |||
| b66e83a57c | |||
| bc103b2e11 | |||
| d28b401aaf | |||
| a79cdd19f8 | |||
| 222f525bf4 | |||
| 317fdcec13 | |||
| 162d6cfa67 | |||
| 2870cc73c2 | |||
| d5097c7964 | |||
| aa3d245cfd | |||
| 61c3f42f10 | |||
| 2dd52c6813 | |||
| 3f82249ed1 | |||
| b49c1c15b7 | |||
| df32dd4966 | |||
| b5d7696dbd | |||
| d2d81ba64a | |||
| b2130f7612 | |||
| 626d274859 | |||
| 9c509680b9 | |||
| 70f81ad1a1 | |||
| c401d1b97f | |||
| eddb0c991b | |||
| 6340ab55e9 | |||
| 86a23b5555 | |||
| 3cb06e07e3 | |||
| c9b44935ed | |||
| 948ba5ec68 | |||
| d0091901dc | |||
| 8c3b83f8b3 | |||
| b031513321 | |||
| c2b379139d | |||
| 6d1d8a0d16 | |||
| dc3c48e469 | |||
| 79dc61ac50 | |||
| 506bb7b29f | |||
| 807af0688f | |||
| 1d9b6099bd | |||
| 5fc7eea754 | |||
| a9716975a7 | |||
| c77d201c49 | |||
| 39107ba107 | |||
| d0e99aada4 | |||
| 71cfba9906 | |||
| b8fe675508 | |||
| 682657ba50 |
@@ -76,7 +76,7 @@ The router caches loaded bots in memory. Cache is **invalidated** by `BotMessage
|
||||
2. Calls `execAgent` with `stepWebhook` and `completionWebhook` pointing at `${INTERNAL_APP_URL ?? APP_URL}/api/agent/webhooks/bot-callback`, plus `webhookDelivery: 'qstash'`.
|
||||
3. Returns immediately; the bridge `finally` block keeps the active-thread marker held until the `completion` callback fires.
|
||||
|
||||
`/api/agent/webhooks/bot-callback/route.ts` verifies the QStash signature and hands off to `BotCallbackService.handleCallback`:
|
||||
`POST /api/agent/webhooks/bot-callback` (`src/server/agent-hono/handlers/botCallback.ts`) verifies the QStash signature via the `qstashAuth` middleware and hands off to `BotCallbackService.handleCallback`:
|
||||
|
||||
- `type: 'step'` → `handleStep` re-renders `renderStepProgress`, edits `progressMessageId` (skipped if `displayToolCalls=false` or platform `supportsMessageEdit=false`).
|
||||
- `type: 'completion'` → `handleCompletion` writes the final reply (or error/interrupted message), removes the 👀 reaction, clears active-thread tracker, fires async `summarizeTopicTitle`.
|
||||
@@ -140,12 +140,12 @@ Webhook platforms run fine in serverless functions. Persistent platforms (`webso
|
||||
- On Vercel + webhook mode → start the client inline (one HTTP call).
|
||||
- Off-Vercel → `GatewayManager` singleton holds long-lived clients in process.
|
||||
|
||||
**`GET /api/agent/gateway/route.ts`** (cron, `Bearer ${CRON_SECRET}`):
|
||||
**`GET /api/agent/gateway`** (`src/server/agent-hono/handlers/gatewayCron.ts`, cron, `Bearer ${CRON_SECRET}`):
|
||||
|
||||
- Iterates registered platforms and starts every enabled persistent provider with `durationMs = 10min`, then in `after(...)` polls `BotConnectQueue` every 30s for new connect requests, until the window expires.
|
||||
- `getEffectiveConnectionMode(platform, settings)` is the only place that resolves per-provider mode — respect it everywhere.
|
||||
|
||||
**`POST /api/agent/gateway/start/route.ts`** is the non-Vercel `ensureRunning` entry point (`Bearer ${KEY_VAULTS_SECRET}`).
|
||||
**`POST /api/agent/gateway/start`** (`src/server/agent-hono/handlers/gatewayStart.ts`) is the non-Vercel `ensureRunning` entry point (`Bearer ${KEY_VAULTS_SECRET}`).
|
||||
|
||||
**Runtime status** is stored in Redis at `bot:runtime-status:platform:appId` with TTL ≈ `durationMs + 60s`. States: `starting | connected | disconnected | failed | queued`. Updated by each `PlatformClient.start/stop` and by the gateway service.
|
||||
|
||||
@@ -226,11 +226,11 @@ Client service: `src/services/agentBotProvider.ts`. Store actions: `src/store/ag
|
||||
## Key Files
|
||||
|
||||
```plaintext
|
||||
Webhook routes:
|
||||
src/app/(backend)/api/agent/webhooks/[platform]/[[...appId]]/route.ts — inbound catch-all
|
||||
src/app/(backend)/api/agent/webhooks/bot-callback/route.ts — qstash bot callback
|
||||
src/app/(backend)/api/agent/gateway/route.ts — cron gateway (10min window)
|
||||
src/app/(backend)/api/agent/gateway/start/route.ts — non-Vercel ensureRunning
|
||||
Webhook routes (mounted via `src/app/(backend)/api/agent/[[...route]]/route.ts` → `src/server/agent-hono`):
|
||||
src/server/agent-hono/handlers/platformWebhook.ts — inbound catch-all (POST /webhooks/:platform/:appId?)
|
||||
src/server/agent-hono/handlers/botCallback.ts — qstash bot callback
|
||||
src/server/agent-hono/handlers/gatewayCron.ts — cron gateway (10min window)
|
||||
src/server/agent-hono/handlers/gatewayStart.ts — non-Vercel ensureRunning
|
||||
|
||||
Bot service:
|
||||
src/server/services/bot/index.ts — barrel
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
---
|
||||
name: builtin-tool
|
||||
description: Build a new builtin tool package under `packages/builtin-tool-<name>/`. Use when adding a new agent-callable toolset, designing its API surface (manifest / ApiName / Params / State), implementing the Executor + ExecutionRuntime, building the Inspector / Render / Placeholder / Streaming / Intervention / Portal UI, or wiring a tool into the central registries (`packages/builtin-tools/src/{index,identifiers,inspectors,renders,placeholders,streamings,interventions,portals}.ts` and `src/store/tool/slices/builtin/executors/index.ts`). Triggers on "new builtin tool", "add a tool", "tool inspector", "tool render", "tool placeholder", "tool streaming", "tool intervention", "BuiltinToolManifest", "BaseExecutor", "ExecutionRuntime".
|
||||
---
|
||||
|
||||
# Builtin Tool Authoring Guide
|
||||
|
||||
A builtin tool is a package the agent runtime can call. It ships **five faces**:
|
||||
|
||||
| Face | Lives in | Audience |
|
||||
| -------------------- | -------------------------------------------------------------------------------------- | ------------------------------------- |
|
||||
| **Manifest + types** | `src/{manifest,types,systemRole}.ts` | The LLM (tool spec + system prompt) |
|
||||
| **ExecutionRuntime** | `src/ExecutionRuntime/` | Server / desktop / any runtime caller |
|
||||
| **Executor** | `src/client/executor/` | Frontend (wraps stores/services) |
|
||||
| **Client UI** | `src/client/{Inspector,Render,…}/` | Chat UI |
|
||||
| **Registry wiring** | `packages/builtin-tools/src/*.ts` + `src/store/tool/slices/builtin/executors/index.ts` | Framework |
|
||||
|
||||
---
|
||||
|
||||
## Read These First
|
||||
|
||||
| Question | Doc |
|
||||
| ------------------------------------------------------------------------------------ | ---------------------------------- |
|
||||
| Where do files live? What does each face do? Wiring? | [architecture.md](architecture.md) |
|
||||
| How do I name the tool, design APIs, write the manifest, executor, ExecutionRuntime? | [tool-design.md](tool-design.md) |
|
||||
| How do I build Inspector / Render / Placeholder / Streaming / Intervention / Portal? | [ui.md](ui.md) |
|
||||
|
||||
---
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
- Creating a new `packages/builtin-tool-<name>/` package
|
||||
- Adding a new API method to an existing builtin tool
|
||||
- Building or restyling any of the 6 client surfaces for a tool
|
||||
- Wiring a tool into the central registries
|
||||
- Debugging "tool not found / API not found / render not showing / placeholder stuck" errors
|
||||
|
||||
---
|
||||
|
||||
## Top-Level Design Principles
|
||||
|
||||
1. **`lobe-<domain>` identifier is permanent.** It's stored in message history. Renames need `@deprecated` aliases (see `packages/builtin-tools/src/inspectors.ts:88-89`). Get it right the first time.
|
||||
2. **ApiName is an `as const` object**, not a TS enum. It doubles as the runtime list `BaseExecutor` iterates over.
|
||||
3. **Three result fields, three audiences:**
|
||||
- `content: string` → the LLM reads it
|
||||
- `state: Record<…>` → the UI's `pluginState`; **result-domain only**, never echo all params back
|
||||
- `error: { type, message, body? }` → both LLM and UI; `type` is a stable code
|
||||
4. **Split execution from frontend wiring.**
|
||||
- `src/ExecutionRuntime/` — pure runtime, no React, no Zustand, accepts services via constructor. **The default place for new logic.**
|
||||
- `src/client/executor/` — `BaseExecutor` subclass that calls `ExecutionRuntime` (or stores/services directly when frontend-only).
|
||||
5. **UI defaults to "do nothing".** Inspector is required (the header strip). Render/Placeholder/Streaming/Intervention/Portal are added **only when there's something specific to show** — empty registries are fine.
|
||||
6. **Style with `createStaticStyles + cssVar.*`** (zero-runtime). Fall back to `createStyles + token` only when you genuinely need runtime values. Use `@lobehub/ui` components, not raw antd.
|
||||
7. **i18n keys live in `src/locales/default/plugin.ts`.** Inspector titles must come from `t('builtins.<identifier>.apiName.<api>')` so something renders while args stream.
|
||||
|
||||
---
|
||||
|
||||
## Package Layout (preferred, post-2026 convention)
|
||||
|
||||
```
|
||||
packages/builtin-tool-<name>/
|
||||
├── package.json
|
||||
└── src/
|
||||
├── index.ts # exports manifest + types + systemRole + Identifier (no React, no stores)
|
||||
├── manifest.ts # BuiltinToolManifest with JSON Schema for every API
|
||||
├── types.ts # ApiName const + Params/State interfaces per API
|
||||
├── systemRole.ts # System prompt teaching the model when/how to use the APIs
|
||||
├── ExecutionRuntime/ # ✅ Default home for runtime logic (server- or anywhere-callable)
|
||||
│ └── index.ts
|
||||
└── client/
|
||||
├── index.ts # Re-exports for the registries
|
||||
├── executor/ # ✅ Frontend executor — extends BaseExecutor, often delegates to ExecutionRuntime
|
||||
│ └── index.ts
|
||||
├── Inspector/ # required — header chip per API
|
||||
├── Render/ # optional — rich result card
|
||||
├── Placeholder/ # optional — skeleton during streaming/execution
|
||||
├── Streaming/ # optional — live output renderer (e.g. RunCommand, WriteFile)
|
||||
├── Intervention/ # optional — approval / edit-before-run UI
|
||||
├── Portal/ # optional — full-screen detail view
|
||||
└── components/ # shared subcomponents used by the surfaces above
|
||||
```
|
||||
|
||||
**Older packages** (`builtin-tool-task`, `builtin-tool-calculator`, etc.) still have `src/executor/` as a sibling of `src/client/`. That's grandfathered; **don't relocate without a deliberate refactor**. New packages and new APIs added to existing packages should follow the layout above.
|
||||
|
||||
`package.json` exports map:
|
||||
|
||||
```json
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./client": "./src/client/index.ts",
|
||||
"./executor": "./src/client/executor/index.ts",
|
||||
"./executionRuntime": "./src/ExecutionRuntime/index.ts"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authoring Checklist
|
||||
|
||||
Before opening the PR:
|
||||
|
||||
- [ ] Identifier follows `lobe-<domain>` and is **stable** (lives in message history).
|
||||
- [ ] Every `<Name>ApiName` value has: a manifest `api[]` entry, an executor method, an Inspector, an i18n `apiName.*` key.
|
||||
- [ ] `Params` interfaces match the JSON Schema; `State` interfaces match what the executor returns and what the UI surfaces read.
|
||||
- [ ] System prompt disambiguates confusable APIs and points to batch variants.
|
||||
- [ ] Runtime logic lives in `ExecutionRuntime/`; the `client/executor/` only wires stores/services and delegates.
|
||||
- [ ] Executor returns `{ success, content, state, error? }` via a single `toResult()` funnel — `content` always non-empty (default to `error.message`).
|
||||
- [ ] Inspector handles `isArgumentsStreaming`, `isLoading`, `partialArgs`, missing `pluginState`.
|
||||
- [ ] Render returns `null` until it has data; only created for APIs with rich results.
|
||||
- [ ] Placeholder added if the API has a perceivable execution lag (search, list, crawl).
|
||||
- [ ] Streaming added for APIs that emit incremental output (run command, write file, code execution).
|
||||
- [ ] Intervention added if `humanIntervention` is set in the manifest.
|
||||
- [ ] All registry files updated (see [architecture.md → Registry wiring](architecture.md#registry-wiring)).
|
||||
- [ ] i18n keys in `src/locales/default/plugin.ts` plus dev seeds in `en-US`/`zh-CN`.
|
||||
- [ ] `bunx vitest run --silent='passed-only' 'packages/builtin-tool-<name>'` passes.
|
||||
- [ ] `bun run type-check` passes.
|
||||
|
||||
---
|
||||
|
||||
## Reference Tools
|
||||
|
||||
Pick the closest neighbor and copy:
|
||||
|
||||
| If your tool is… | Read first |
|
||||
| ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
||||
| Pure-compute, no UI state | `packages/builtin-tool-calculator/` — `ExecutionRuntime` reuses executor (mathjs/nerdamer work everywhere) |
|
||||
| CRUD over a domain entity | `packages/builtin-tool-task/` — full Inspector + Render set, batch variants |
|
||||
| Heavy UI (Inspector/Render/Placeholder/Portal) | `packages/builtin-tool-web-browsing/` — search-style result UI, Portal for detail view |
|
||||
| Desktop / filesystem with all surfaces (incl. Streaming + Intervention) | `packages/builtin-tool-local-system/` — `ExecutionRuntime` injects an `ILocalSystemService`, executor calls it |
|
||||
| Server-side pure (no client executor) | `packages/builtin-tool-web-browsing/` — only `ExecutionRuntime` is exported; the chat client doesn't run it |
|
||||
| Needs human approval before running | `packages/builtin-tool-local-system/src/client/Intervention/` — per-API approval components |
|
||||
@@ -0,0 +1,315 @@
|
||||
# Builtin Tool Architecture
|
||||
|
||||
## The Five Faces
|
||||
|
||||
A builtin tool ships five distinct faces, each compiled into a different bundle:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ./ │
|
||||
│ Manifest + Types + systemRole │
|
||||
│ ─ Pure data, no React, no Node-only deps. │
|
||||
│ ─ Imported by: server (LLM tool spec), client (registries), │
|
||||
│ anyone who needs to know "what tools exist". │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ./executionRuntime │
|
||||
│ src/ExecutionRuntime/index.ts │
|
||||
│ ─ Pure runtime logic. Accepts services via constructor — │
|
||||
│ never imports concrete services or stores directly. │
|
||||
│ ─ Imported by: server (BuiltinServerRuntimeOutput), tests, │
|
||||
│ and the client executor as a delegate. │
|
||||
│ ─ Returns: BuiltinServerRuntimeOutput { content, state, … } │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ./executor │
|
||||
│ src/client/executor/index.ts │
|
||||
│ ─ BaseExecutor subclass. Wires Zustand stores and frontend │
|
||||
│ services into ExecutionRuntime, then funnels through │
|
||||
│ toResult() into BuiltinToolResult { content, state, error, │
|
||||
│ success }. │
|
||||
│ ─ Imported by: src/store/tool/slices/builtin/executors/ │
|
||||
│ index.ts (registered as a singleton). │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ./client │
|
||||
│ src/client/{Inspector,Render,Placeholder,Streaming, │
|
||||
│ Intervention,Portal,components}/ │
|
||||
│ ─ React 'use client' surfaces. Read args + pluginState. │
|
||||
│ ─ Imported by: packages/builtin-tools/src/{inspectors, │
|
||||
│ renders,placeholders,streamings,interventions,portals}.ts. │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Registry wiring │
|
||||
│ packages/builtin-tools/src/*.ts │
|
||||
│ src/store/tool/slices/builtin/executors/index.ts │
|
||||
│ ─ Aggregator maps: identifier → { apiName → component }. │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
The split exists so:
|
||||
|
||||
- Server bundles import only `./` and `./executionRuntime` and never touch React.
|
||||
- Frontend bundles import `./client` and never touch Node-only services.
|
||||
- The runtime is testable without React or Electron present.
|
||||
|
||||
---
|
||||
|
||||
## Why ExecutionRuntime is the Default Home for Logic
|
||||
|
||||
**Old pattern (grandfathered):** business logic in `src/executor/` directly. Examples: `builtin-tool-task`, older tools. Works, but the executor mixes runtime logic with frontend service plumbing — hard to reuse on the server.
|
||||
|
||||
**New pattern (preferred):** business logic in `src/ExecutionRuntime/`, frontend wiring in `src/client/executor/`. Examples: `builtin-tool-local-system`, `builtin-tool-web-browsing`, `builtin-tool-calculator`.
|
||||
|
||||
```
|
||||
ExecutionRuntime
|
||||
├─ accepts services via constructor (or `static create(opts)`)
|
||||
├─ returns BuiltinServerRuntimeOutput (content + state + success)
|
||||
└─ no React, no Zustand, no `@/services/...` direct imports
|
||||
|
||||
client/executor
|
||||
├─ extends BaseExecutor<typeof <Name>ApiName>
|
||||
├─ holds a `runtime = new <Name>ExecutionRuntime(realService)` instance
|
||||
├─ each ApiName method:
|
||||
│ 1. resolve scope / pull defaults from BuiltinToolContext
|
||||
│ 2. call runtime.<method>(args)
|
||||
│ 3. funnel through toResult() → BuiltinToolResult
|
||||
└─ exported singleton: export const <name>Executor = new <Name>Executor()
|
||||
```
|
||||
|
||||
### Service injection
|
||||
|
||||
`ExecutionRuntime` should declare a TypeScript interface for the services it needs and accept the implementation via constructor. Server callers wire in real implementations; tests wire in mocks. Example from `local-system`:
|
||||
|
||||
```ts
|
||||
export interface ILocalSystemService {
|
||||
readLocalFile: (params: any) => Promise<any>;
|
||||
writeFile: (params: any) => Promise<any>;
|
||||
/* … */
|
||||
}
|
||||
|
||||
export class LocalSystemExecutionRuntime extends ComputerRuntime {
|
||||
constructor(private service: ILocalSystemService) {
|
||||
super();
|
||||
}
|
||||
/* methods delegate to this.service.* */
|
||||
}
|
||||
```
|
||||
|
||||
The `client/executor` instantiates it once with the real service:
|
||||
|
||||
```ts
|
||||
import { localFileService } from '@/services/electron/localFileService';
|
||||
import { LocalSystemExecutionRuntime } from '../../ExecutionRuntime';
|
||||
|
||||
class LocalSystemExecutor extends BaseExecutor<typeof LocalSystemApiEnum> {
|
||||
private runtime = new LocalSystemExecutionRuntime(localFileService);
|
||||
/* … */
|
||||
}
|
||||
```
|
||||
|
||||
### When ExecutionRuntime is the only thing you ship
|
||||
|
||||
Some tools are server-only — there's no frontend executor. `builtin-tool-web-browsing` is the canonical example: only `./` and `./executionRuntime` are exported, no `./executor`, and the runtime is constructed by the server-side `ToolExecutionService`. Skip `client/executor/` entirely for those.
|
||||
|
||||
### When the executor reuses the runtime as-is
|
||||
|
||||
Pure-compute tools (`builtin-tool-calculator`) often have an executor whose ApiName methods call `executor.calculate(args)` and an `ExecutionRuntime` whose methods call `calculatorExecutor.calculate(args)` — same logic, two thin wrappers. That's fine; the duplication buys you the bundle split.
|
||||
|
||||
---
|
||||
|
||||
## The Result Contract
|
||||
|
||||
### `BuiltinServerRuntimeOutput` (what ExecutionRuntime returns)
|
||||
|
||||
```ts
|
||||
{
|
||||
content: string; // the LLM-facing text — never undefined; default to error message
|
||||
state?: any; // result-domain object the UI reads as pluginState
|
||||
success: boolean; // mandatory
|
||||
error?: any; // raw error; the executor will repackage
|
||||
}
|
||||
```
|
||||
|
||||
### `BuiltinToolResult` (what the executor returns to the runtime)
|
||||
|
||||
```ts
|
||||
{
|
||||
success: boolean;
|
||||
content?: string;
|
||||
state?: any;
|
||||
error?: { type: string; message: string; body?: any };
|
||||
metadata?: Record<string, any>; // rare; e.g. { agentCouncil: true }
|
||||
stop?: boolean; // rare; halt the orchestration step
|
||||
}
|
||||
```
|
||||
|
||||
### The `toResult` funnel (mandatory)
|
||||
|
||||
Every executor method returns through a single `toResult()` to enforce two invariants:
|
||||
|
||||
1. **`content` is never undefined.** A missing content collapses downstream into `''`, leaving the Debug pane blank while `pluginState` was already saved. See the `globLocalFiles` regression in `local-system/src/client/executor/index.ts:60-84`.
|
||||
2. **`state` survives failures.** Renderers can keep showing partial output even when `success: false`.
|
||||
|
||||
```ts
|
||||
private toResult(output: BuiltinServerRuntimeOutput): BuiltinToolResult {
|
||||
const errorMessage = typeof output.error?.message === 'string' ? output.error.message : undefined;
|
||||
const safeContent = output.content || errorMessage || 'Tool execution failed';
|
||||
|
||||
if (!output.success) {
|
||||
return {
|
||||
success: false,
|
||||
content: safeContent,
|
||||
state: output.state,
|
||||
error: output.error
|
||||
? { type: 'PluginServerError', message: errorMessage ?? safeContent, body: output.error }
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
return { success: true, content: safeContent, state: output.state };
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `BaseExecutor` — How Method Dispatch Works
|
||||
|
||||
`BaseExecutor.invoke(apiName, params, ctx)` does:
|
||||
|
||||
```ts
|
||||
if (!this.hasApi(apiName)) return { error: { type: 'ApiNotFound', … }, success: false };
|
||||
return (this as any)[apiName](params, ctx); // method name MUST equal apiName value
|
||||
```
|
||||
|
||||
So:
|
||||
|
||||
- **Method names must equal `<Name>ApiName` values, exactly.** A typo silently routes to "ApiNotFound".
|
||||
- **Methods must be class fields, not class methods**, because `this` is lost when registry calls `executor.invoke(apiName, params, ctx)`. Always declare as `methodName = async (…) => { … }`.
|
||||
- **Always destructure `apiEnum` and `identifier` as `readonly` instance fields**, not getters — `BaseExecutor.hasApi/getApiNames` reads them synchronously.
|
||||
|
||||
---
|
||||
|
||||
## `BuiltinToolContext` — What the Executor Receives
|
||||
|
||||
The runtime hands every executor method an optional `BuiltinToolContext` as the second argument:
|
||||
|
||||
| Field | Use |
|
||||
| ----------------------------- | -------------------------------------------------------------- |
|
||||
| `agentId` | Default agent for "current agent" semantics (e.g. `listTasks`) |
|
||||
| `groupId` | Group chat scope |
|
||||
| `topicId` | Current topic — needed when creating messages/operations |
|
||||
| `taskId` | Current task identifier — fallback for "implicit" param |
|
||||
| `documentId` | Current page/document scope |
|
||||
| `messageId` | The tool message being created (for state attachments) |
|
||||
| `sourceMessageId` | The user message that triggered this tool turn |
|
||||
| `operationId` | Operation lineage (use for cancellation, tracing) |
|
||||
| `scope` | `'task' \| 'agent' \| …` — toggles default behaviors |
|
||||
| `signal: AbortSignal` | Honor for long-running ops |
|
||||
| `stepContext` | Cross-message runtime state (GTD todos, etc.) |
|
||||
| `registerAfterCompletion(cb)` | Defer side-effects past message-update race |
|
||||
| `groupOrchestration` | Group orchestration callbacks |
|
||||
|
||||
**Use rule:** read with `?.`, fall back to explicit params, **never silently override** an explicit param with a context value.
|
||||
|
||||
---
|
||||
|
||||
## i18n Integration
|
||||
|
||||
Source of truth: `src/locales/default/plugin.ts`. Keys follow `builtins.<identifier>.<topic>.<…>`:
|
||||
|
||||
| Key | Use |
|
||||
| ------------------------------------- | ------------------------------------------------------------ |
|
||||
| `builtins.<identifier>.title` | Display title (overrides `manifest.meta.title` when present) |
|
||||
| `builtins.<identifier>.apiName.<api>` | Inspector header label (one per ApiName) |
|
||||
| `builtins.<identifier>.inspector.<…>` | Extra Inspector strings ("no results", chips, counters) |
|
||||
| `builtins.<identifier>.<feature>.<…>` | Render / Intervention strings, free-form per tool |
|
||||
|
||||
For dev preview, also seed `locales/zh-CN/plugin.json` and `locales/en-US/plugin.json`. Run `pnpm i18n` before opening a PR — it's slow, so do it once at the end. (See the **i18n** skill for the full workflow.)
|
||||
|
||||
---
|
||||
|
||||
## Registry Wiring
|
||||
|
||||
Five core files plus optional ones. Miss any and you'll see "tool not found", a missing chip, a blank result card, a stuck spinner, or an approval dialog that never appears.
|
||||
|
||||
| File | Add what |
|
||||
| -------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| **Required** | |
|
||||
| `packages/builtin-tools/src/index.ts` | Import `<Name>Manifest`; push entry to `builtinTools`. Set `hidden`/`discoverable` flags. |
|
||||
| `packages/builtin-tools/src/identifiers.ts` | Add `<Name>Manifest.identifier` to `builtinToolIdentifiers`. |
|
||||
| `packages/builtin-tools/src/inspectors.ts` | Import `<Name>Inspectors, <Name>Manifest`; add to `BuiltinToolInspectors`. |
|
||||
| `src/store/tool/slices/builtin/executors/index.ts` | Import `<name>Executor`; add to `registerExecutors([…])`. |
|
||||
| **Conditional — add only if the surface exists** | |
|
||||
| `packages/builtin-tools/src/renders.ts` | Add to `BuiltinToolsRenders` if any API has a Render. |
|
||||
| `packages/builtin-tools/src/placeholders.ts` | Add to `BuiltinToolPlaceholders` if any API has a Placeholder. |
|
||||
| `packages/builtin-tools/src/streamings.ts` | Add to `BuiltinToolStreamings` if any API has a Streaming renderer. |
|
||||
| `packages/builtin-tools/src/interventions.ts` | Add to `BuiltinToolInterventions` if any API has an Intervention component. |
|
||||
| `packages/builtin-tools/src/portals.ts` | Add to `BuiltinToolsPortals` if the tool has a Portal. |
|
||||
| `packages/builtin-tools/src/displayControls.ts` | Add if Render must show/hide based on result content (rare; see ClaudeCode/Codex). |
|
||||
|
||||
### Optional flags in `packages/builtin-tools/src/index.ts`
|
||||
|
||||
```ts
|
||||
{
|
||||
identifier: TaskManifest.identifier,
|
||||
manifest: TaskManifest,
|
||||
type: 'builtin',
|
||||
hidden: true, // hide from chat-input Tools popover
|
||||
discoverable: false, // exclude from agent builder / skill discovery
|
||||
}
|
||||
```
|
||||
|
||||
Lists in the same file you may need to touch:
|
||||
|
||||
- `defaultToolIds` — added to the agent's tool list by default
|
||||
- `alwaysOnToolIds` — forced on regardless of user selection (use sparingly)
|
||||
- `runtimeManagedToolIds` — enable state controlled by runtime, not user UI; **must mirror the rules map** in `src/server/modules/Mecha/AgentToolsEngine/index.ts` and `src/helpers/toolEngineering/index.ts`
|
||||
|
||||
---
|
||||
|
||||
## File-Map at a Glance
|
||||
|
||||
```
|
||||
packages/builtin-tool-<name>/
|
||||
├── package.json # exports: ., ./client, ./executor, ./executionRuntime
|
||||
└── src/
|
||||
├── index.ts # export Manifest, Identifier, types, systemPrompt
|
||||
├── manifest.ts # BuiltinToolManifest + Identifier const
|
||||
├── types.ts # ApiName + Params/State per API
|
||||
├── systemRole.ts # System prompt (multiple variants OK: systemRole.desktop.ts)
|
||||
├── ExecutionRuntime/
|
||||
│ └── index.ts # <Name>ExecutionRuntime — pure runtime, service injection
|
||||
└── client/
|
||||
├── index.ts # exports for the registries
|
||||
├── executor/
|
||||
│ └── index.ts # <Name>Executor extends BaseExecutor; export <name>Executor
|
||||
├── Inspector/
|
||||
│ ├── index.ts # <Name>Inspectors record
|
||||
│ └── <ApiName>/index.tsx # one folder per API (or .tsx file when trivial)
|
||||
├── Render/
|
||||
│ ├── index.ts # <Name>Renders record
|
||||
│ └── <ApiName>/ # rich renders → folder with subcomponents
|
||||
├── Placeholder/
|
||||
│ ├── index.ts
|
||||
│ └── <ApiName>.tsx # usually a single skeleton file
|
||||
├── Streaming/
|
||||
│ ├── index.ts
|
||||
│ └── <ApiName>/ # live-output renderer
|
||||
├── Intervention/
|
||||
│ ├── index.ts
|
||||
│ └── <ApiName>/ # approval / edit-before-run UI
|
||||
├── Portal/
|
||||
│ ├── index.tsx # routing component (switch on apiName)
|
||||
│ └── <ApiName>/ # full-screen detail view
|
||||
└── components/ # FileItem, EngineAvatar, etc. — shared subcomponents
|
||||
```
|
||||
|
||||
Skip every `client/<surface>/` directory you don't need — empty registries are fine.
|
||||
@@ -0,0 +1,478 @@
|
||||
# Tool Design (Naming, Manifest, Executor, Runtime)
|
||||
|
||||
This doc covers everything that **isn't UI**: the tool's identifier, API surface, manifest, types, system prompt, ExecutionRuntime, and the executor that wires it into the frontend.
|
||||
|
||||
For UI surfaces (Inspector / Render / Placeholder / Streaming / Intervention / Portal), see [ui.md](ui.md).
|
||||
For where files live and how registries work, see [architecture.md](architecture.md).
|
||||
|
||||
---
|
||||
|
||||
## 1. Naming
|
||||
|
||||
| Thing | Convention | Example |
|
||||
| ----------------------- | -------------------------------------------------------------- | ------------------------------------------------------------ |
|
||||
| Package directory | `packages/builtin-tool-<kebab>/` | `builtin-tool-task` |
|
||||
| npm name | `@lobechat/builtin-tool-<kebab>` | `@lobechat/builtin-tool-task` |
|
||||
| Tool `identifier` | `lobe-<kebab-domain>` — **persisted in message history** | `lobe-task`, `lobe-calculator`, `lobe-knowledge-base` |
|
||||
| Identifier const | `<Name>Identifier` exported from `manifest.ts` (or `types.ts`) | `export const TaskIdentifier = 'lobe-task'` |
|
||||
| API name const | `<Name>ApiName` — `as const` object, **camelCase verbs** | `createTask`, `listTasks`, `runTask` |
|
||||
| Executor class | `<Name>Executor extends BaseExecutor<typeof <Name>ApiName>` | `TaskExecutor` |
|
||||
| Executor singleton | `<name>Executor` (camelCase) | `export const taskExecutor = new TaskExecutor()` |
|
||||
| ExecutionRuntime class | `<Name>ExecutionRuntime` | `LocalSystemExecutionRuntime`, `WebBrowsingExecutionRuntime` |
|
||||
| Inspector / Render etc. | `<ApiName>Inspector` / `<ApiName>Render` | `CreateTaskInspector`, `SearchInspector` |
|
||||
|
||||
### Identifier rules
|
||||
|
||||
- **`lobe-` prefix is mandatory** — many switches in the codebase key off it.
|
||||
- Pick a **domain noun**, not a verb (`lobe-task`, not `lobe-task-manager`).
|
||||
- The identifier is **persisted in message history** — renaming after release means the `@deprecated` alias trick (register the legacy identifier as a second key in `inspectors.ts` / `renders.ts` pointing at the new module). Get it right the first time.
|
||||
|
||||
### ApiName rules
|
||||
|
||||
- Verb + noun, camelCase: `createTask`, `viewTask`, `runTasks`.
|
||||
- **Plural variant for batch** (`createTasks`, `runTasks`) — describe in the manifest description that it's preferred over multiple single calls. The system prompt should also push the batch form.
|
||||
- Reserve **clear separation between mutating verbs** (`updateTaskStatus`, `editTask`) and **execution verbs** (`runTask`). The system prompt must warn the model when these are confusable — see `task` for the canonical "do NOT use updateTaskStatus(running) to start a task" warning.
|
||||
- Read-only verbs: `list*`, `view*`, `get*`, `search*`. Mutating: `create*`, `edit*`, `update*`, `delete*`. Triggers/effects: `run*`, `execute*`, `submit*`.
|
||||
|
||||
---
|
||||
|
||||
## 2. `types.ts` — ApiName + Params/State
|
||||
|
||||
Define `<Name>ApiName` as `as const` so it doubles as a runtime enum (used by `BaseExecutor`) and a literal type. Then declare `Params` and `State` per API.
|
||||
|
||||
```ts
|
||||
export const TaskIdentifier = 'lobe-task';
|
||||
|
||||
export const TaskApiName = {
|
||||
createTask: 'createTask',
|
||||
createTasks: 'createTasks',
|
||||
listTasks: 'listTasks',
|
||||
/* …one entry per API, group logically (CRUD then run-style) */
|
||||
} as const;
|
||||
|
||||
export type TaskApiNameType = (typeof TaskApiName)[keyof typeof TaskApiName];
|
||||
|
||||
// One block per API
|
||||
export interface CreateTaskParams {
|
||||
name: string;
|
||||
instruction: string; /* … */
|
||||
}
|
||||
export interface CreateTaskState {
|
||||
identifier?: string;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export interface CreateTasksParams {
|
||||
tasks: CreateTaskParams[];
|
||||
}
|
||||
export interface CreateTasksItemResult {
|
||||
error?: string;
|
||||
identifier?: string;
|
||||
name: string;
|
||||
success: boolean;
|
||||
}
|
||||
export interface CreateTasksState {
|
||||
failed: number;
|
||||
results: CreateTasksItemResult[];
|
||||
succeeded: number;
|
||||
}
|
||||
```
|
||||
|
||||
**The result-domain rule for `State`** (memory: "pluginState is result-domain, not call-domain"):
|
||||
|
||||
- Include only fields the UI **renders after the call returns** — ids the LLM didn't have when calling, counts, summary numbers, server-assigned status.
|
||||
- **Don't echo all params.** The Inspector/Render gets `args` for free.
|
||||
- Keep batch results as `{ succeeded, failed, results }` so the Render can show a one-line summary plus a detail list.
|
||||
|
||||
---
|
||||
|
||||
## 3. `manifest.ts` — JSON Schema for the LLM
|
||||
|
||||
```ts
|
||||
import type { BuiltinToolManifest } from '@lobechat/types';
|
||||
|
||||
import { systemPrompt } from './systemRole';
|
||||
import { TaskApiName, TaskIdentifier } from './types';
|
||||
|
||||
export const TaskManifest: BuiltinToolManifest = {
|
||||
identifier: TaskIdentifier,
|
||||
type: 'builtin',
|
||||
systemRole: systemPrompt,
|
||||
meta: {
|
||||
avatar: '📋',
|
||||
title: 'Task Tools',
|
||||
description: 'Create, list, edit, delete tasks with dependencies',
|
||||
readme: 'Optional long description shown in tool detail pages',
|
||||
},
|
||||
api: [
|
||||
{
|
||||
name: TaskApiName.createTask,
|
||||
description:
|
||||
'Create a new task. Optionally attach as a subtask via parentIdentifier. ' +
|
||||
'Prefer createTasks when planning a batch.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['name', 'instruction'],
|
||||
properties: {
|
||||
name: { type: 'string', description: 'Short, descriptive name.' },
|
||||
instruction: {
|
||||
type: 'string',
|
||||
description: 'Detailed instruction for what the task should accomplish.',
|
||||
},
|
||||
parentIdentifier: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Identifier of the parent task (e.g. "TASK-1"). If provided, the new task becomes a subtask.',
|
||||
},
|
||||
priority: {
|
||||
type: 'number',
|
||||
description: 'Priority level: 0=none, 1=urgent, 2=high, 3=normal, 4=low. Default is 0.',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
/* …one entry per ApiName */
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Manifest writing checklist
|
||||
|
||||
- **Every API in `<Name>ApiName` has exactly one entry in `api[]`.** Easy to drift after a refactor.
|
||||
- **`description` on each API is the model's only docs.** Make it long enough for the LLM to pick the right tool. Mention edge cases ("If you provide any filter, omitted filters are not applied implicitly"), defaults, and the relationship to sibling APIs ("To START a task, use runTask — updateTaskStatus only flips a flag").
|
||||
- **`parameters` is JSON Schema** (`LobeChatPluginApi`). Use `enum`, `required`, `items`, `oneOf`, `additionalProperties: false` etc. — these survive into the LLM's tool spec.
|
||||
- **Use `additionalProperties: false`** on parameter objects so the model can't sneak unknown fields past validation.
|
||||
- **Number parameters with semantic values** (`priority: 0=none, 1=urgent, …`) should describe the mapping in the description. Don't rely on `enum` alone for numbers — the model often fills the wrong one.
|
||||
- **`enum` arrays for known string sets** (statuses, categories, engines). Spread from a constants module (`enum: [...TASK_STATUSES]`) so the manifest stays in sync.
|
||||
|
||||
### Optional manifest fields
|
||||
|
||||
```ts
|
||||
{
|
||||
/* Where this tool can run.
|
||||
'client' → Agent Gateway dispatches to the desktop client (filesystem, Electron only)
|
||||
'server' → ToolExecutionService runs it on the server
|
||||
omitted → server only */
|
||||
executors: ['client', 'server'],
|
||||
|
||||
/* Default human intervention policy for all APIs that don't specify one.
|
||||
Pair with an Intervention component (see ui.md). */
|
||||
humanIntervention: 'never' | 'always' | { /* extended config */ },
|
||||
}
|
||||
```
|
||||
|
||||
Per-API `humanIntervention` and `renderDisplayControl` go inside each `api[]` entry.
|
||||
|
||||
---
|
||||
|
||||
## 4. `systemRole.ts` — Operator Instructions for the Model
|
||||
|
||||
This is appended to the agent system prompt whenever the tool is enabled. Treat it as a **how-to-use guide for the LLM**, not marketing copy.
|
||||
|
||||
```ts
|
||||
export const systemPrompt = `You have access to Task management tools. Use them to:
|
||||
|
||||
- **createTask**: Create a new task. Use parentIdentifier to make it a subtask.
|
||||
- **createTasks**: Prefer this over multiple createTask calls when planning a batch
|
||||
(e.g. all subtasks under one parent, or all chapters of an outline).
|
||||
- **runTask**: Actually START a task — kicks off the agent in a new (or continued)
|
||||
topic. Do NOT use updateTaskStatus(running) to start a task; that only flips a
|
||||
flag without executing. The task must have an assigneeAgentId.
|
||||
- **updateTaskStatus**: Change a task's status (completed/cancelled/paused/failed).
|
||||
If you mark a task as failed, include an error message explaining why.
|
||||
- ...
|
||||
|
||||
When planning work:
|
||||
1. Create tasks for each major piece (use parentIdentifier to organize as subtasks).
|
||||
2. Use editTask with addDependencies to control execution order.
|
||||
3. Use updateTaskStatus to mark the current task completed when done.`;
|
||||
```
|
||||
|
||||
### Patterns that work well
|
||||
|
||||
- **Bulleted list, bold the API name, one line per API.** The model picks tools by skimming.
|
||||
- **Disambiguate confusable APIs explicitly** (`runTask` vs `updateTaskStatus`).
|
||||
- **Push toward batched APIs** ("Prefer this when…").
|
||||
- **End with a numbered workflow** if the tool has a typical sequence.
|
||||
- **For tools with multiple environments** (e.g. desktop vs cloud), keep variants in `systemRole.ts` and `systemRole.desktop.ts` and pick at the manifest level. See `builtin-tool-local-system`.
|
||||
|
||||
### Dynamic system prompts
|
||||
|
||||
If the prompt depends on runtime state (current date, available models), export a function and call it in the manifest:
|
||||
|
||||
```ts
|
||||
// systemRole.ts
|
||||
export const systemPrompt = (today: string) => `Today is ${today}. You have web search tools…`;
|
||||
|
||||
// manifest.ts
|
||||
import dayjs from 'dayjs';
|
||||
systemRole: systemPrompt(dayjs(new Date()).format('YYYY-MM-DD')),
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. `ExecutionRuntime/index.ts` — Pure Runtime
|
||||
|
||||
This is **the default home for new tool logic** going forward. The runtime is a class that:
|
||||
|
||||
- Has no React, no Zustand, no `@/services/...` direct imports.
|
||||
- Receives services as **constructor injection** (or as method args).
|
||||
- Returns `BuiltinServerRuntimeOutput` from each method.
|
||||
- Is unit-testable by passing in mocks.
|
||||
|
||||
### Pattern A: Inject a service interface
|
||||
|
||||
Use when the runtime calls out to IPC, network, or DB.
|
||||
|
||||
```ts
|
||||
// ExecutionRuntime/index.ts
|
||||
import type { BuiltinServerRuntimeOutput } from '@lobechat/types';
|
||||
|
||||
export interface IWebBrowsingService {
|
||||
search: (q: SearchQuery) => Promise<UniformSearchResponse>;
|
||||
crawlPages: (urls: string[]) => Promise<CrawlResults>;
|
||||
}
|
||||
|
||||
export interface WebBrowsingRuntimeOptions {
|
||||
searchService: IWebBrowsingService;
|
||||
documentService?: WebBrowsingDocumentService;
|
||||
agentId?: string;
|
||||
topicId?: string;
|
||||
}
|
||||
|
||||
export class WebBrowsingExecutionRuntime {
|
||||
constructor(private opts: WebBrowsingRuntimeOptions) {}
|
||||
|
||||
async search(
|
||||
args: SearchQuery,
|
||||
options?: { signal?: AbortSignal },
|
||||
): Promise<BuiltinServerRuntimeOutput> {
|
||||
try {
|
||||
const data = await this.opts.searchService.search(args, options);
|
||||
if (data.errorDetail) {
|
||||
return {
|
||||
success: false,
|
||||
content: data.errorDetail,
|
||||
error: { message: data.errorDetail },
|
||||
state: data,
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
content: searchResultsPrompt(data.results.slice(0, 10)),
|
||||
state: data,
|
||||
};
|
||||
} catch (e) {
|
||||
return { success: false, content: (e as Error).message, error: e };
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern B: Reuse the executor
|
||||
|
||||
Use when the same logic runs in browser and Node (e.g. mathjs, nerdamer). The runtime is a thin wrapper that imports the executor and re-types the state per API. See `builtin-tool-calculator/src/ExecutionRuntime/index.ts` for the canonical example.
|
||||
|
||||
### Pattern C: Extend a shared base
|
||||
|
||||
When you're implementing a domain that already has a base runtime (file ops via `ComputerRuntime`), extend and only override `callService` + result normalization. See `builtin-tool-local-system/src/ExecutionRuntime/index.ts`.
|
||||
|
||||
### Runtime contract
|
||||
|
||||
Every method returns:
|
||||
|
||||
```ts
|
||||
{
|
||||
content: string; // LLM-facing — never undefined; default to error message
|
||||
state?: any; // result-domain — what the UI's pluginState becomes
|
||||
success: boolean; // mandatory
|
||||
error?: any; // raw error object; the executor will repackage
|
||||
}
|
||||
```
|
||||
|
||||
Use `@lobechat/prompts` formatters (`searchResultsPrompt`, `crawlResultsPrompt`, `formatTaskCreated`, etc.) to produce structured `content`. They emit XML/markdown that's already tuned for token efficiency.
|
||||
|
||||
---
|
||||
|
||||
## 6. `client/executor/index.ts` — Frontend Wiring
|
||||
|
||||
The executor's job is to **resolve frontend defaults** (current agent, current task, scope) and **call the runtime**. It then funnels through `toResult()` into the `BuiltinToolResult` shape.
|
||||
|
||||
```ts
|
||||
import { BaseExecutor, type BuiltinToolContext, type BuiltinToolResult } from '@lobechat/types';
|
||||
import debug from 'debug';
|
||||
|
||||
import { taskService } from '@/services/task';
|
||||
import { getTaskStoreState } from '@/store/task';
|
||||
|
||||
import { TaskIdentifier } from '../../manifest';
|
||||
import { TaskApiName, type CreateTaskParams } from '../../types';
|
||||
|
||||
const log = debug('lobe-task:executor');
|
||||
|
||||
class TaskExecutor extends BaseExecutor<typeof TaskApiName> {
|
||||
readonly identifier = TaskIdentifier;
|
||||
protected readonly apiEnum = TaskApiName;
|
||||
|
||||
// ⚠ class FIELD, not a method — preserves `this` when invoked via registry
|
||||
createTask = async (
|
||||
params: CreateTaskParams,
|
||||
ctx?: BuiltinToolContext,
|
||||
): Promise<BuiltinToolResult> => {
|
||||
try {
|
||||
log('createTask params=%o', params);
|
||||
const task = await getTaskStoreState().createTask({
|
||||
name: params.name,
|
||||
instruction: params.instruction,
|
||||
// Default assignee from context — never silently override an explicit value
|
||||
assigneeAgentId:
|
||||
params.assigneeAgentId ?? (ctx?.scope === 'task' ? undefined : ctx?.agentId),
|
||||
parentTaskId: params.parentIdentifier?.trim() || undefined,
|
||||
priority: params.priority,
|
||||
});
|
||||
|
||||
if (!task) return this.errorResult('Failed to create task', 'CreateFailed');
|
||||
|
||||
return {
|
||||
success: true,
|
||||
content: formatTaskCreated({ identifier: task.identifier, name: task.name /* … */ }),
|
||||
state: { identifier: task.identifier, success: true },
|
||||
};
|
||||
} catch (error) {
|
||||
return this.errorResult(error, 'CreateTaskFailed');
|
||||
}
|
||||
};
|
||||
|
||||
private errorResult(err: unknown, type: string): BuiltinToolResult {
|
||||
const message = err instanceof Error ? err.message : String(err) || 'Unknown error';
|
||||
return { success: false, content: `Failed: ${message}`, error: { type, message } };
|
||||
}
|
||||
}
|
||||
|
||||
export const taskExecutor = new TaskExecutor();
|
||||
```
|
||||
|
||||
### Hard rules
|
||||
|
||||
1. **Methods are class fields** (`name = async (…) => {…}`), not class methods. The registry calls `(executor as any)[apiName](params, ctx)`; arrow-function fields keep `this` bound.
|
||||
2. **`identifier` and `apiEnum` are `readonly` instance fields**, not getters — `BaseExecutor.hasApi/getApiNames` reads them synchronously at registration time.
|
||||
3. **Default missing params from `ctx`**, but never silently override explicit values. Use `params.foo ?? ctx?.foo`, not `ctx?.foo ?? params.foo`.
|
||||
4. **One funnel for all returns.** Either always return through `toResult(runtime.x())` (when delegating) or through `errorResult(…)` for the catch arm. Never inline `{ success: false, content: '' }` — `content: ''` collapses the Debug pane to blank.
|
||||
5. **`debug('lobe-<name>:executor')`.** Match the namespace to the identifier minus `lobe-` when convenient.
|
||||
6. **Singleton export.** `export const <name>Executor = new <Name>Executor()` — the registry imports the instance, not the class.
|
||||
|
||||
### When the executor delegates to ExecutionRuntime
|
||||
|
||||
```ts
|
||||
class LocalSystemExecutor extends BaseExecutor<typeof LocalSystemApiEnum> {
|
||||
readonly identifier = LocalSystemIdentifier;
|
||||
protected readonly apiEnum = LocalSystemApiEnum;
|
||||
private runtime = new LocalSystemExecutionRuntime(localFileService);
|
||||
|
||||
readLocalFile = async (params: LocalReadFileParams): Promise<BuiltinToolResult> => {
|
||||
try {
|
||||
const result = await this.runtime.readFile({
|
||||
path: params.path,
|
||||
startLine: params.loc?.[0],
|
||||
endLine: params.loc?.[1],
|
||||
});
|
||||
return this.toResult(result);
|
||||
} catch (error) {
|
||||
return this.errorResult(error);
|
||||
}
|
||||
};
|
||||
|
||||
private toResult(out: BuiltinServerRuntimeOutput): BuiltinToolResult {
|
||||
const errMsg = typeof out.error?.message === 'string' ? out.error.message : undefined;
|
||||
const safe = out.content || errMsg || 'Tool execution failed';
|
||||
if (!out.success) {
|
||||
return {
|
||||
success: false,
|
||||
content: safe,
|
||||
state: out.state, // ← preserve partial state on failure
|
||||
error: out.error
|
||||
? { type: 'PluginServerError', message: errMsg ?? safe, body: out.error }
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
return { success: true, content: safe, state: out.state };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `toResult` funnel is **mandatory**: it enforces never-undefined `content` and partial-state preservation. Both invariants caught real production bugs (`globLocalFiles` Response empty, `editLocalFile` partial state lost).
|
||||
|
||||
---
|
||||
|
||||
## 7. `index.ts` — Package Entry Point
|
||||
|
||||
Keep it pure data + the manifest. **No React, no stores, no Node-only imports.**
|
||||
|
||||
```ts
|
||||
export { TaskIdentifier, TaskManifest } from './manifest';
|
||||
export { systemPrompt } from './systemRole';
|
||||
export {
|
||||
TaskApiName,
|
||||
type TaskApiNameType,
|
||||
type CreateTaskParams,
|
||||
type CreateTaskState,
|
||||
/* …all Params/State types */
|
||||
} from './types';
|
||||
|
||||
// Optional helpers used by both the runtime and the UI
|
||||
export { TASK_STATUSES, UNFINISHED_TASK_STATUSES } from './constants';
|
||||
```
|
||||
|
||||
This entry is what `packages/builtin-tools/src/index.ts` and `identifiers.ts` import — it must be importable from server bundles.
|
||||
|
||||
---
|
||||
|
||||
## 8. `package.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@lobechat/prompts": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lobechat/types": "workspace:*"
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./client": "./src/client/index.ts",
|
||||
"./executor": "./src/client/executor/index.ts",
|
||||
"./executionRuntime": "./src/ExecutionRuntime/index.ts"
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"name": "@lobechat/builtin-tool-<name>",
|
||||
"peerDependencies": {
|
||||
"@lobehub/ui": "^5",
|
||||
"antd": "^6",
|
||||
"antd-style": "*",
|
||||
"lucide-react": "*",
|
||||
"react": "*",
|
||||
"react-i18next": "*"
|
||||
},
|
||||
"private": true,
|
||||
"version": "1.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
**Why peer not direct deps for client libs:** the `./` and `./executionRuntime` entry points must be importable from server code. Listing React etc. as peer deps prevents bundlers from following them when only the runtime is consumed.
|
||||
|
||||
**Skip `./executor`** if the package has no frontend executor (server-only tools like `builtin-tool-web-browsing`).
|
||||
|
||||
---
|
||||
|
||||
## 9. Common Pitfalls
|
||||
|
||||
| Symptom | Likely cause |
|
||||
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| "ApiNotFound" at runtime | Method name in executor doesn't match `ApiName` value (typo, wrong case) |
|
||||
| Method works once, then "this is undefined" | Method declared as `async fn() {}` instead of `fn = async () => {}` — `this` lost when registry invokes |
|
||||
| Debug "Response" pane blank but `pluginState` populated | Returning `content: ''` or letting `output.content` be undefined — use the `toResult` funnel |
|
||||
| Partial result vanishes on failure | `toResult` discarded `state` when `success: false`; preserve it |
|
||||
| Tool shows up but doesn't run on desktop | `executors` in manifest doesn't include `'client'` (or vice versa for server-only) |
|
||||
| Same tool registered twice / legacy identifier ghost | Identifier collision; check `@deprecated` aliases in `inspectors.ts`/`renders.ts` |
|
||||
| Manifest test fails after adding API | Forgot to add the corresponding i18n `apiName.<api>` key |
|
||||
| TypeScript error on `BaseExecutor<typeof X>` | `X` declared with `enum` instead of `as const` object — must be the const-object form |
|
||||
@@ -0,0 +1,721 @@
|
||||
# Tool UI Surfaces
|
||||
|
||||
A builtin tool can ship up to **six client-side surfaces**, each with a different role in the chat UI. Only `Inspector` is required; the other five are added on demand and registered in their own central files.
|
||||
|
||||
| Surface | Required? | When the chat shows it | Registered in |
|
||||
| ------------ | --------- | --------------------------------------------------------------------- | --------------------------------------------- |
|
||||
| Inspector | ✅ Always | Header strip of every tool call (one-line chip) | `packages/builtin-tools/src/inspectors.ts` |
|
||||
| Render | Optional | Rich result card below the header, after the call returns | `packages/builtin-tools/src/renders.ts` |
|
||||
| Placeholder | Optional | Skeleton between "args streaming complete" and "result arrives" | `packages/builtin-tools/src/placeholders.ts` |
|
||||
| Streaming | Optional | Live output during execution (e.g. command stdout) | `packages/builtin-tools/src/streamings.ts` |
|
||||
| Intervention | Optional | Approval / edit-before-run dialog (when `humanIntervention` triggers) | `packages/builtin-tools/src/interventions.ts` |
|
||||
| Portal | Optional | Full-screen detail view (right-side or modal) | `packages/builtin-tools/src/portals.ts` |
|
||||
|
||||
The two reference tools to read end-to-end:
|
||||
|
||||
- **`builtin-tool-web-browsing/src/client/`** — Inspector + Render + Placeholder + Portal (no Intervention/Streaming).
|
||||
- **`builtin-tool-local-system/src/client/`** — all six surfaces, including `components/` for shared building blocks.
|
||||
|
||||
---
|
||||
|
||||
## 0. Shared Style Rules
|
||||
|
||||
These apply across every surface.
|
||||
|
||||
### 0.1 Use `'use client'` at the top of every component file
|
||||
|
||||
Tool surfaces are leaves in the chat tree and must not block server rendering.
|
||||
|
||||
### 0.2 Prefer `createStaticStyles + cssVar.*`
|
||||
|
||||
Zero-runtime CSS-in-JS — the styles compile once and read CSS variables at runtime.
|
||||
|
||||
```tsx
|
||||
import { createStaticStyles, cssVar } from 'antd-style';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
chip: css`
|
||||
padding-block: 2px;
|
||||
padding-inline: 8px;
|
||||
border-radius: 999px;
|
||||
color: ${cssVar.colorText};
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
Fall back to `createStyles + token` only when you need runtime token computation (rare). Inline `style={{ color: cssVar.colorTextSecondary }}` is fine for one-off dynamic values.
|
||||
|
||||
### 0.3 Use `@lobehub/ui`, not raw `antd`
|
||||
|
||||
`Block`, `Text`, `Flexbox`, `Highlighter`, `Alert`, `Tooltip`, `Skeleton` all come from `@lobehub/ui`. Modals come from `@lobehub/ui/base-ui` (`createModal`, `useModalContext`, `confirmModal`) — see the **modal** skill.
|
||||
|
||||
Memory note: `@lobehub/ui`'s `<Text type='secondary'>` is a lighter shade than `colorTextSecondary`. If you need that exact token color, write `<Text style={{ color: cssVar.colorTextSecondary }}>`.
|
||||
|
||||
### 0.4 Always `memo` and set `displayName`
|
||||
|
||||
```tsx
|
||||
export const SearchInspector = memo<BuiltinInspectorProps<SearchQuery, UniformSearchResponse>>(
|
||||
({ args /* … */ }) => {
|
||||
/* … */
|
||||
},
|
||||
);
|
||||
SearchInspector.displayName = 'SearchInspector';
|
||||
export default SearchInspector;
|
||||
```
|
||||
|
||||
### 0.5 Always type with `BuiltinXProps<Args, State>` generics
|
||||
|
||||
Don't widen to `any`. The Args generic is the JSON Schema params, the State generic is the executor's `state` field. The two should match `<Name>Params` and `<Name>State` from `types.ts`.
|
||||
|
||||
### 0.6 Pull strings from `t('plugin')`
|
||||
|
||||
```tsx
|
||||
const { t } = useTranslation('plugin');
|
||||
t('builtins.<identifier>.apiName.<api>');
|
||||
```
|
||||
|
||||
Every Inspector should default to `t('builtins.<identifier>.apiName.<api>')` so it shows something while args stream in.
|
||||
|
||||
### 0.7 Read store state from `@/store/chat`, not props
|
||||
|
||||
Tool surfaces sometimes need cross-cutting state (loading, streaming buffer). Read it inside the component via Zustand selectors, not from props — props only carry args/state/messageId.
|
||||
|
||||
---
|
||||
|
||||
## 1. Inspector — Header Chip (required)
|
||||
|
||||
**Lifecycle:** Inspector renders for **every phase** of a tool call: while args are streaming in, while the executor is running, and after results come back. It's the only surface that's always visible.
|
||||
|
||||
**Goal:** keep it to a single line. Show what's happening with as much context as is currently available.
|
||||
|
||||
### Props (`BuiltinInspectorProps<Args, State>`)
|
||||
|
||||
```ts
|
||||
interface BuiltinInspectorProps<Arguments = any, State = any> {
|
||||
apiName: string;
|
||||
args: Arguments; // final args (only after the assistant stops streaming)
|
||||
identifier: string;
|
||||
isArgumentsStreaming?: boolean; // args still arriving
|
||||
isLoading?: boolean; // args complete, executor running
|
||||
partialArgs?: Arguments; // partial JSON during streaming
|
||||
pluginState?: State; // executor's `state` after success
|
||||
result?: { content: string | null; error?: any };
|
||||
}
|
||||
```
|
||||
|
||||
### State machine
|
||||
|
||||
| Phase | What's available | What to show |
|
||||
| ----------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------- |
|
||||
| Args streaming, no useful field yet | `isArgumentsStreaming === true`, `partialArgs.X` undefined | Just the API title with `shinyTextStyles.shinyText` |
|
||||
| Args streaming, key field arrived | `partialArgs.X` populated | Title + key field chip, still pulse-animated |
|
||||
| Args complete, executor running | `args` populated, `isLoading === true` | Same as above, still pulse-animated |
|
||||
| Result arrived | `pluginState` populated, `isLoading === false` | Title + chips + result summary (count, identifier, status) |
|
||||
|
||||
### Canonical example — Search
|
||||
|
||||
`packages/builtin-tool-web-browsing/src/client/Inspector/Search/index.tsx`:
|
||||
|
||||
```tsx
|
||||
'use client';
|
||||
|
||||
import type { BuiltinInspectorProps, SearchQuery, UniformSearchResponse } from '@lobechat/types';
|
||||
import { Text } from '@lobehub/ui';
|
||||
import { cssVar, cx } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { highlightTextStyles, inspectorTextStyles, shinyTextStyles } from '@/styles';
|
||||
|
||||
export const SearchInspector = memo<BuiltinInspectorProps<SearchQuery, UniformSearchResponse>>(
|
||||
({ args, partialArgs, isArgumentsStreaming, isLoading, pluginState }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
const query = args?.query || partialArgs?.query || '';
|
||||
const resultCount = pluginState?.results?.length ?? 0;
|
||||
const hasResults = resultCount > 0;
|
||||
|
||||
if (isArgumentsStreaming && !query) {
|
||||
return (
|
||||
<div className={cx(inspectorTextStyles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-web-browsing.apiName.search')}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
inspectorTextStyles.root,
|
||||
(isArgumentsStreaming || isLoading) && shinyTextStyles.shinyText,
|
||||
)}
|
||||
>
|
||||
<span>{t('builtins.lobe-web-browsing.apiName.search')}: </span>
|
||||
{query && <span className={highlightTextStyles.primary}>{query}</span>}
|
||||
{!isLoading &&
|
||||
!isArgumentsStreaming &&
|
||||
pluginState?.results &&
|
||||
(hasResults ? (
|
||||
<span style={{ marginInlineStart: 4 }}>({resultCount})</span>
|
||||
) : (
|
||||
<Text as="span" color={cssVar.colorTextDescription} fontSize={12}>
|
||||
({t('builtins.lobe-web-browsing.inspector.noResults')})
|
||||
</Text>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
SearchInspector.displayName = 'SearchInspector';
|
||||
export default SearchInspector;
|
||||
```
|
||||
|
||||
### Inspector rules
|
||||
|
||||
- Wrap the whole row with `inspectorTextStyles.root` (provides correct flex / line-height baseline).
|
||||
- Pulse with `shinyTextStyles.shinyText` whenever `isArgumentsStreaming || isLoading`.
|
||||
- Show the i18n title first so the row is non-empty during the earliest streaming phase.
|
||||
- Read both `args?.X` and `partialArgs?.X` together — `args` is final, `partialArgs` is in-stream.
|
||||
- Use chips/tags for distinct facets (identifier, name, parent, status, count). Each chip should clip with `text-overflow: ellipsis` and have a `max-width` so long values don't blow out the chat bubble.
|
||||
- Append `pluginState`-derived suffixes only **after** loading finishes — count or "(no results)" should not appear while still searching.
|
||||
|
||||
### Inspector registry — `client/Inspector/index.ts`
|
||||
|
||||
```ts
|
||||
import type { BuiltinInspector } from '@lobechat/types';
|
||||
|
||||
import { TaskApiName } from '../../types';
|
||||
import { CreateTaskInspector } from './CreateTask';
|
||||
import { ListTasksInspector } from './ListTasks';
|
||||
/* … */
|
||||
|
||||
export const TaskInspectors: Record<string, BuiltinInspector> = {
|
||||
[TaskApiName.createTask]: CreateTaskInspector as BuiltinInspector,
|
||||
[TaskApiName.listTasks]: ListTasksInspector as BuiltinInspector,
|
||||
/* one entry per ApiName */
|
||||
};
|
||||
|
||||
export { CreateTaskInspector } from './CreateTask';
|
||||
export { ListTasksInspector } from './ListTasks';
|
||||
/* re-export each */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Render — Rich Result Card (optional)
|
||||
|
||||
**Lifecycle:** rendered **once the result arrives** (after Placeholder/Streaming hand off). Sits below the Inspector header.
|
||||
|
||||
**Skip if** the API is read-only or the result is just text — the framework already shows the executor's `content` string. Add a Render only when there's a structured artifact worth seeing: a card, a chart, a diff, a list of files.
|
||||
|
||||
### Props (`BuiltinRenderProps<Args, State, Content>`)
|
||||
|
||||
```ts
|
||||
interface BuiltinRenderProps<Arguments = any, State = any, Content = any> {
|
||||
apiName?: string;
|
||||
args: Arguments; // final params from the LLM
|
||||
content: Content; // executor's content string (or parsed)
|
||||
identifier?: string;
|
||||
messageId: string; // for store lookups
|
||||
pluginError?: any; // from BuiltinToolResult.error
|
||||
pluginState?: State; // executor's state
|
||||
toolCallId?: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Two patterns
|
||||
|
||||
**Pattern A — Single-file Render** (web-browsing CrawlSinglePage):
|
||||
|
||||
```tsx
|
||||
// client/Render/CrawlSinglePage.tsx
|
||||
import type { BuiltinRenderProps, CrawlPluginState, CrawlSinglePageQuery } from '@lobechat/types';
|
||||
import { memo } from 'react';
|
||||
|
||||
import PageContent from './PageContent';
|
||||
|
||||
const CrawlSinglePage = memo<BuiltinRenderProps<CrawlSinglePageQuery, CrawlPluginState>>(
|
||||
({ messageId, pluginState, args }) => (
|
||||
<PageContent messageId={messageId} results={pluginState?.results} urls={[args?.url]} />
|
||||
),
|
||||
);
|
||||
export default CrawlSinglePage;
|
||||
```
|
||||
|
||||
**Pattern B — Folder with subcomponents** (web-browsing Search):
|
||||
|
||||
```
|
||||
client/Render/Search/
|
||||
├── index.tsx # composes the subcomponents, handles error states
|
||||
├── ConfigForm.tsx # appears when pluginError.type === 'PluginSettingsInvalid'
|
||||
├── SearchQuery.tsx # editable query header
|
||||
└── SearchResult.tsx # result list
|
||||
```
|
||||
|
||||
Use Pattern B when the Render has internal state (editing mode, expanded items), error variants, or is large enough to benefit from splitting.
|
||||
|
||||
### Error handling in Render
|
||||
|
||||
Renders are the canonical place to surface `pluginError` because the chat doesn't auto-render typed errors:
|
||||
|
||||
```tsx
|
||||
if (pluginError) {
|
||||
if (pluginError?.type === 'PluginSettingsInvalid') {
|
||||
return <ConfigForm id={messageId} provider={pluginError.body?.provider} />;
|
||||
}
|
||||
return (
|
||||
<Alert
|
||||
title={pluginError?.message}
|
||||
type="error"
|
||||
extra={<Highlighter language="json">{JSON.stringify(pluginError.body, null, 2)}</Highlighter>}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Render rules
|
||||
|
||||
- **Return `null`** if there's nothing useful to draw yet (avoids empty cards during stream).
|
||||
- Use `pluginState` for server-truth (ids, counts, server-assigned status) and `args` for what the LLM asked. **Combine — neither alone is enough.**
|
||||
- For lists, summarize with a header line and show top N items with a "+N more" tail rather than rendering everything.
|
||||
- For modals from a Render, use `@lobehub/ui/base-ui` (`createModal`, `useModalContext`, `confirmModal`) — see the **modal** skill.
|
||||
|
||||
### Render registry — `client/Render/index.ts`
|
||||
|
||||
```ts
|
||||
import type { BuiltinRender } from '@lobechat/types';
|
||||
|
||||
import { TaskApiName } from '../../types';
|
||||
import CreateTaskRender from './CreateTask';
|
||||
import RunTasksRender from './RunTasks';
|
||||
|
||||
export const TaskRenders: Record<string, BuiltinRender> = {
|
||||
[TaskApiName.createTask]: CreateTaskRender as BuiltinRender,
|
||||
[TaskApiName.runTasks]: RunTasksRender as BuiltinRender,
|
||||
/* only the APIs with rich result UI — others fall back to text content */
|
||||
};
|
||||
|
||||
export { default as CreateTaskRender } from './CreateTask';
|
||||
export { default as RunTasksRender } from './RunTasks';
|
||||
```
|
||||
|
||||
### Render display control (rare)
|
||||
|
||||
If the Render should hide for certain results (e.g. ClaudeCode's TodoWrite hides when the agent is mid-stream), add a `RenderDisplayControl` to `packages/builtin-tools/src/displayControls.ts`. See `ClaudeCodeRenderDisplayControls` for the pattern.
|
||||
|
||||
---
|
||||
|
||||
## 3. Placeholder — Skeleton Between Args and Result (optional)
|
||||
|
||||
**Lifecycle:** rendered when the args have finished streaming but the executor hasn't returned yet. Disappears when `pluginState` arrives. Bridges the moment of perceived lag.
|
||||
|
||||
**Add for** APIs with noticeable execution time: web search, network crawl, file list, large grep. **Skip for** instant ops (status flips, calculator).
|
||||
|
||||
### Props (`BuiltinPlaceholderProps<Args>`)
|
||||
|
||||
```ts
|
||||
interface BuiltinPlaceholderProps<T extends Record<string, any> = any> {
|
||||
apiName: string;
|
||||
args?: T;
|
||||
identifier: string;
|
||||
}
|
||||
```
|
||||
|
||||
No `pluginState` — Placeholder lives entirely in the "executing" gap.
|
||||
|
||||
### Canonical example — Search Placeholder
|
||||
|
||||
`packages/builtin-tool-web-browsing/src/client/Placeholder/Search.tsx`:
|
||||
|
||||
```tsx
|
||||
import type { BuiltinPlaceholderProps, SearchQuery } from '@lobechat/types';
|
||||
import { Flexbox, Icon, Skeleton } from '@lobehub/ui';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { SearchIcon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { useIsMobile } from '@/hooks/useIsMobile';
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
query: cx(
|
||||
css`
|
||||
padding: 4px 8px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
&:hover {
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
}
|
||||
`,
|
||||
shinyTextStyles.shinyText,
|
||||
),
|
||||
}));
|
||||
|
||||
export const Search = memo<BuiltinPlaceholderProps<SearchQuery>>(({ args }) => {
|
||||
const { query } = args || {};
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return (
|
||||
<Flexbox gap={8}>
|
||||
<Flexbox horizontal={!isMobile} gap={isMobile ? 8 : 40}>
|
||||
<Flexbox horizontal align="center" className={styles.query} gap={8}>
|
||||
<Icon icon={SearchIcon} />
|
||||
{query ? query : <Skeleton.Block active style={{ height: 20, width: 40 }} />}
|
||||
</Flexbox>
|
||||
<Skeleton.Block active style={{ height: 20, width: 40 }} />
|
||||
</Flexbox>
|
||||
<Flexbox horizontal gap={12}>
|
||||
{[1, 2, 3, 4, 5].map((id) => (
|
||||
<Skeleton.Button active key={id} style={{ borderRadius: 8, height: 80, width: 160 }} />
|
||||
))}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### Placeholder rules
|
||||
|
||||
- **Mirror the eventual Render's layout.** When the result arrives the Placeholder unmounts and the Render mounts; if they share dimensions, the chat doesn't jump.
|
||||
- Use `Skeleton.Block` / `Skeleton.Button` from `@lobehub/ui` for placeholder shapes.
|
||||
- Embed any args you have (e.g. the query text) — context helps the user know what's loading.
|
||||
- Pulse with `shinyTextStyles.shinyText` if the Placeholder includes literal text.
|
||||
|
||||
### Placeholder registry — `client/Placeholder/index.ts`
|
||||
|
||||
```ts
|
||||
import { WebBrowsingApiName } from '../../types';
|
||||
import CrawlMultiPages from './CrawlMultiPages';
|
||||
import CrawlSinglePage from './CrawlSinglePage';
|
||||
import { Search } from './Search';
|
||||
|
||||
export const WebBrowsingPlaceholders = {
|
||||
[WebBrowsingApiName.crawlMultiPages]: CrawlMultiPages,
|
||||
[WebBrowsingApiName.crawlSinglePage]: CrawlSinglePage,
|
||||
[WebBrowsingApiName.search]: Search,
|
||||
};
|
||||
|
||||
export { CrawlMultiPages, CrawlSinglePage, Search };
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Streaming — Live Output During Execution (optional)
|
||||
|
||||
**Lifecycle:** rendered **while the executor is still running** for APIs that emit incremental output. The component is responsible for fetching the in-flight stream from the chat store and rendering it.
|
||||
|
||||
**Add for** long-running ops with continuous output: shell command execution (stdout/stderr), file write progress, code interpreter cells.
|
||||
|
||||
### Props (`BuiltinStreamingProps<Args>`)
|
||||
|
||||
```ts
|
||||
interface BuiltinStreamingProps<Arguments = any> {
|
||||
apiName: string;
|
||||
args: Arguments;
|
||||
identifier: string;
|
||||
messageId: string; // use to fetch the streaming buffer from store
|
||||
toolCallId: string;
|
||||
}
|
||||
```
|
||||
|
||||
Note there's **no `state` or `result` prop** — the Streaming component is for the in-flight phase. It pulls the live buffer from the store itself (typically via `chatToolSelectors.streamingContent(messageId)` or similar).
|
||||
|
||||
### Canonical example — RunCommandStreaming
|
||||
|
||||
`packages/builtin-tool-local-system/src/client/Streaming/RunCommand/index.tsx`:
|
||||
|
||||
```tsx
|
||||
'use client';
|
||||
|
||||
import type { BuiltinStreamingProps } from '@lobechat/types';
|
||||
import { Highlighter } from '@lobehub/ui';
|
||||
import { memo } from 'react';
|
||||
|
||||
interface RunCommandParams {
|
||||
command?: string;
|
||||
description?: string;
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
export const RunCommandStreaming = memo<BuiltinStreamingProps<RunCommandParams>>(({ args }) => {
|
||||
const { command } = args || {};
|
||||
if (!command) return null;
|
||||
|
||||
return (
|
||||
<Highlighter
|
||||
animated
|
||||
wrap
|
||||
language="sh"
|
||||
showLanguage={false}
|
||||
style={{ padding: '4px 8px' }}
|
||||
variant="outlined"
|
||||
>
|
||||
{command}
|
||||
</Highlighter>
|
||||
);
|
||||
});
|
||||
RunCommandStreaming.displayName = 'RunCommandStreaming';
|
||||
```
|
||||
|
||||
For real-time output beyond just the command (stderr/stdout streaming), pull from the chat store:
|
||||
|
||||
```tsx
|
||||
const buffer = useChatStore((state) =>
|
||||
chatToolSelectors.streamingBuffer(messageId, toolCallId)(state),
|
||||
);
|
||||
```
|
||||
|
||||
### Streaming rules
|
||||
|
||||
- Render `null` until you have something to display (avoids flash).
|
||||
- For terminal-style output, use `Highlighter` with `animated` to show typing-like effect.
|
||||
- The Streaming component must **unmount cleanly** when execution ends — typically the framework swaps it out for the Render automatically.
|
||||
|
||||
### Streaming registry — `client/Streaming/index.ts`
|
||||
|
||||
```ts
|
||||
import { LocalSystemApiName } from '../..';
|
||||
import { RunCommandStreaming } from './RunCommand';
|
||||
import { WriteFileStreaming } from './WriteFile';
|
||||
|
||||
export const LocalSystemStreamings = {
|
||||
[LocalSystemApiName.runCommand]: RunCommandStreaming,
|
||||
[LocalSystemApiName.writeLocalFile]: WriteFileStreaming,
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Intervention — Approval / Edit-Before-Run (optional)
|
||||
|
||||
**Lifecycle:** rendered **before the executor runs** for APIs whose manifest sets `humanIntervention`. The user sees a preview of the args, can edit them, then approves or skips/cancels.
|
||||
|
||||
**Add for** destructive or sensitive ops: shell commands, file writes, file moves, payments, message broadcasts.
|
||||
|
||||
### Props (`BuiltinInterventionProps<Args>`)
|
||||
|
||||
```ts
|
||||
interface BuiltinInterventionProps<Arguments = any> {
|
||||
apiName?: string;
|
||||
args: Arguments;
|
||||
identifier?: string;
|
||||
interactionMode?: 'approval' | 'custom';
|
||||
messageId: string;
|
||||
|
||||
/** Called when the user edits the args; the approve action awaits this. */
|
||||
onArgsChange?: (args: Arguments) => void | Promise<void>;
|
||||
|
||||
/** Called on approve / skip / cancel. */
|
||||
onInteractionAction?: (
|
||||
action:
|
||||
| { type: 'submit'; payload: Record<string, unknown> }
|
||||
| { type: 'skip'; payload?: Record<string, unknown>; reason?: string }
|
||||
| { type: 'cancel'; payload?: Record<string, unknown> },
|
||||
) => Promise<void>;
|
||||
|
||||
/** Register a callback to flush pending saves before approval. Returns cleanup. */
|
||||
registerBeforeApprove?: (id: string, callback: () => void | Promise<void>) => () => void;
|
||||
}
|
||||
```
|
||||
|
||||
### Canonical example — RunCommand Intervention
|
||||
|
||||
`packages/builtin-tool-local-system/src/client/Intervention/RunCommand/index.tsx`:
|
||||
|
||||
```tsx
|
||||
import type { RunCommandParams } from '@lobechat/electron-client-ipc';
|
||||
import type { BuiltinInterventionProps } from '@lobechat/types';
|
||||
import { Flexbox, Highlighter, Text } from '@lobehub/ui';
|
||||
import { memo } from 'react';
|
||||
|
||||
const RunCommand = memo<BuiltinInterventionProps<RunCommandParams>>(({ args }) => {
|
||||
const { description, command, timeout } = args;
|
||||
return (
|
||||
<Flexbox gap={8}>
|
||||
<Flexbox horizontal justify="space-between">
|
||||
{description && <Text>{description}</Text>}
|
||||
{timeout && (
|
||||
<Text style={{ fontSize: 12 }} type="secondary">
|
||||
timeout: {formatTimeout(timeout)}
|
||||
</Text>
|
||||
)}
|
||||
</Flexbox>
|
||||
{command && (
|
||||
<Highlighter wrap language="sh" showLanguage={false} variant="outlined">
|
||||
{command}
|
||||
</Highlighter>
|
||||
)}
|
||||
</Flexbox>
|
||||
);
|
||||
});
|
||||
export default RunCommand;
|
||||
```
|
||||
|
||||
### Intervention rules
|
||||
|
||||
- **Show a preview, not a form by default.** Editing UI is opt-in via `onArgsChange` and is usually inline (click to edit a code block, etc.).
|
||||
- For args with debounced edit state (text fields), use `registerBeforeApprove(id, flushFn)` so the approve action waits for the debounce to flush. Always return the cleanup function.
|
||||
- Call `onInteractionAction({ type: 'submit', payload })` when the user approves; `'skip'` if they skip with a reason; `'cancel'` if they cancel the whole turn.
|
||||
- Add a corresponding `interventionAudit.ts` in the package root if the tool needs scope/path validation before approval (see `local-system/src/interventionAudit.ts`).
|
||||
|
||||
### Intervention registry — `client/Intervention/index.ts`
|
||||
|
||||
```ts
|
||||
import { LocalSystemApiName } from '../..';
|
||||
import EditLocalFile from './EditLocalFile';
|
||||
import RunCommand from './RunCommand';
|
||||
import WriteFile from './WriteFile';
|
||||
/* … */
|
||||
|
||||
export const LocalSystemInterventions = {
|
||||
[LocalSystemApiName.editLocalFile]: EditLocalFile,
|
||||
[LocalSystemApiName.runCommand]: RunCommand,
|
||||
[LocalSystemApiName.writeLocalFile]: WriteFile,
|
||||
/* one entry per API that needs approval */
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Portal — Full-Screen Detail View (optional)
|
||||
|
||||
**Lifecycle:** rendered when the user opens the tool message in a side panel or full-screen modal. One Portal per **tool**, not per API — the Portal switches on `apiName` internally.
|
||||
|
||||
**Add for** tools whose results deserve a deep-dive view: search results with editable filters, page content with reader mode, code interpreter sessions.
|
||||
|
||||
### Props (`BuiltinPortalProps<Args, State>`)
|
||||
|
||||
```ts
|
||||
interface BuiltinPortalProps<Arguments = Record<string, any>, State = any> {
|
||||
apiName?: string;
|
||||
arguments: Arguments;
|
||||
identifier: string;
|
||||
messageId: string;
|
||||
state: State;
|
||||
}
|
||||
```
|
||||
|
||||
### Canonical example — Web-Browsing Portal
|
||||
|
||||
`packages/builtin-tool-web-browsing/src/client/Portal/index.tsx`:
|
||||
|
||||
```tsx
|
||||
import type { BuiltinPortalProps, CrawlPluginState, SearchQuery } from '@lobechat/types';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { WebBrowsingApiName } from '../../types';
|
||||
import PageContent from './PageContent';
|
||||
import PageContents from './PageContents';
|
||||
import Search from './Search';
|
||||
|
||||
const Portal = memo<BuiltinPortalProps>(({ arguments: args, messageId, state, apiName }) => {
|
||||
switch (apiName) {
|
||||
case WebBrowsingApiName.search:
|
||||
return <Search messageId={messageId} query={args as SearchQuery} response={state} />;
|
||||
|
||||
case WebBrowsingApiName.crawlSinglePage: {
|
||||
const result = (state as CrawlPluginState).results.find((r) => r.originalUrl === args.url);
|
||||
return <PageContent messageId={messageId} result={result} />;
|
||||
}
|
||||
|
||||
case WebBrowsingApiName.crawlMultiPages:
|
||||
return (
|
||||
<PageContents
|
||||
messageId={messageId}
|
||||
results={(state as CrawlPluginState).results}
|
||||
urls={args.urls}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
export default Portal;
|
||||
```
|
||||
|
||||
### Portal rules
|
||||
|
||||
- One Portal per tool — the file is the routing layer, subcomponents implement each API's view.
|
||||
- Portals can read the chat store directly to detect "still streaming" and render a Skeleton internally (see `Search/index.tsx:20-46`).
|
||||
- Layout assumes more space than the Render — use `Flexbox` with `height={'100%'}` and structure for a side panel viewport.
|
||||
|
||||
### Portal registry — `packages/builtin-tools/src/portals.ts`
|
||||
|
||||
```ts
|
||||
import { WebBrowsingManifest, WebBrowsingPortal } from '@lobechat/builtin-tool-web-browsing/client';
|
||||
import { type BuiltinPortal } from '@lobechat/types';
|
||||
|
||||
export const BuiltinToolsPortals: Record<string, BuiltinPortal> = {
|
||||
[WebBrowsingManifest.identifier]: WebBrowsingPortal as BuiltinPortal,
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. `client/components/` — Shared Subcomponents
|
||||
|
||||
Cross-cutting building blocks used by multiple surfaces live here, not duplicated in each surface folder.
|
||||
|
||||
Examples from `web-browsing/src/client/components/`:
|
||||
|
||||
- `CategoryAvatar.tsx` — search category icon
|
||||
- `EngineAvatar.tsx` — search engine logo (used in Inspector chip + Render list + Portal header)
|
||||
- `SearchBar.tsx` — editable query bar (used in Render and Portal)
|
||||
|
||||
Examples from `local-system/src/client/components/`:
|
||||
|
||||
- `FileItem.tsx` — single file row (used in ListFiles Render, SearchFiles Render, MoveLocalFiles Render)
|
||||
- `FilePathDisplay.tsx` — path with truncation (used everywhere)
|
||||
|
||||
### Rules
|
||||
|
||||
- Live under `client/components/`, exported via `client/components/index.ts`.
|
||||
- Re-export from `client/index.ts` only if other packages need them; otherwise keep internal.
|
||||
- Keep them dumb — props in, JSX out, no store reads. The store reads belong in the surface that composes them.
|
||||
|
||||
---
|
||||
|
||||
## 8. `client/index.ts` — Package Public API
|
||||
|
||||
Re-exports everything the registries need plus useful types/manifest:
|
||||
|
||||
```ts
|
||||
// Inspector — required
|
||||
export { TaskInspectors } from './Inspector';
|
||||
|
||||
// Render — only if any API has one
|
||||
export { TaskRenders, CreateTaskRender, RunTasksRender } from './Render';
|
||||
|
||||
// Placeholder / Streaming / Intervention — only if used
|
||||
export { LocalSystemListFilesPlaceholder, LocalSystemSearchFilesPlaceholder } from './Placeholder';
|
||||
export { LocalSystemStreamings } from './Streaming';
|
||||
export { LocalSystemInterventions } from './Intervention';
|
||||
|
||||
// Portal — single export per tool
|
||||
export { default as WebBrowsingPortal } from './Portal';
|
||||
|
||||
// Reusable components if other packages need them
|
||||
export { CategoryAvatar, EngineAvatar, SearchBar } from './components';
|
||||
|
||||
// Re-export manifest, identifier, types for convenience
|
||||
export { TaskManifest, TaskIdentifier } from '../manifest';
|
||||
export * from '../types';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Diagnostic Quick-Lookup
|
||||
|
||||
| Symptom | Surface to check | | |
|
||||
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | --- | ------------------------- |
|
||||
| No header at all on the tool call | Inspector missing from `client/Inspector/index.ts` registry | | |
|
||||
| Header shows the API name but no chips | Inspector missing \`args?.X | | partialArgs?.X\` fallback |
|
||||
| Header doesn't pulse during loading | Missing `shinyTextStyles.shinyText` on `isArgumentsStreaming \|\| isLoading` | | |
|
||||
| Empty result card under header | Render returned `<div />` instead of `null` when no data | | |
|
||||
| Layout jump when result arrives | Placeholder dimensions don't match Render dimensions | | |
|
||||
| Approval dialog never appears | Manifest missing `humanIntervention`, or Intervention not in registry | | |
|
||||
| Approval click doesn't wait for inline edit | Missing `registerBeforeApprove(id, flushFn)` | | |
|
||||
| Portal opens but blank | Switch in `Portal/index.tsx` doesn't cover the apiName | | |
|
||||
| Strings show as `builtins.lobe-foo.apiName.bar` | Missing i18n key in `src/locales/default/plugin.ts` (or not seeded in dev locale files) | | |
|
||||
| Wrong color shade on `<Text type="secondary">` | `type='secondary'` is lighter than `colorTextSecondary` — pass via `style={{ color: cssVar.colorTextSecondary }}` | | |
|
||||
@@ -11,86 +11,167 @@
|
||||
# Environment variables:
|
||||
# CDP_PORT — Chrome DevTools Protocol port (default: 9222)
|
||||
# ELECTRON_LOG — Log file path (default: /tmp/electron-dev.log)
|
||||
# ELECTRON_WAIT_S — Max seconds to wait for Electron process (default: 60)
|
||||
# RENDERER_WAIT_S — Max seconds to wait for renderer/SPA (default: 60)
|
||||
# ELECTRON_WAIT_S — Max seconds to wait for CDP to become reachable (default: 90)
|
||||
# RENDERER_WAIT_S — Max seconds to wait for SPA after CDP is up (default: 60)
|
||||
# FORCE_KILL_USER — When set to 1, silently kill the user's `bun run dev`
|
||||
# Electron without confirmation (default: always confirm-by-action)
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
CDP_PORT="${CDP_PORT:-9222}"
|
||||
ELECTRON_LOG="${ELECTRON_LOG:-/tmp/electron-dev.log}"
|
||||
ELECTRON_WAIT_S="${ELECTRON_WAIT_S:-60}"
|
||||
ELECTRON_WAIT_S="${ELECTRON_WAIT_S:-90}"
|
||||
RENDERER_WAIT_S="${RENDERER_WAIT_S:-60}"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
|
||||
PIDFILE="/tmp/electron-dev-cdp-${CDP_PORT}.pid"
|
||||
|
||||
# Project-scoped electron path prefix used for pgrep matching. Any Electron
|
||||
# binary from this project (main + helpers, with or without --remote-debugging-port)
|
||||
# starts with this string in its argv[0], so a single substring match catches all.
|
||||
PROJECT_ELECTRON_PATH="${PROJECT_ROOT}/apps/desktop/node_modules/.pnpm/electron@"
|
||||
|
||||
# ── Helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
# Get the Electron binary path used by this project
|
||||
electron_bin_pattern() {
|
||||
echo "${PROJECT_ROOT}/apps/desktop/node_modules/.pnpm/electron@*/node_modules/electron/dist/Electron.app"
|
||||
# Print pid + every descendant pid (DFS via pgrep -P).
|
||||
expand_descendants() {
|
||||
local pid="$1"
|
||||
echo "$pid"
|
||||
local children
|
||||
children=$(pgrep -P "$pid" 2>/dev/null || true)
|
||||
for c in $children; do
|
||||
expand_descendants "$c"
|
||||
done
|
||||
}
|
||||
|
||||
# Find all PIDs related to the project's Electron dev session
|
||||
find_electron_pids() {
|
||||
# Find seed PIDs related to this project's Electron dev session.
|
||||
# Matches REGARDLESS of whether --remote-debugging-port was passed, so it also
|
||||
# catches a plain `bun run dev` session the user started outside this script.
|
||||
find_project_pids() {
|
||||
local pids=""
|
||||
|
||||
# 1. Main Electron process (launched with --remote-debugging-port)
|
||||
local main_pids
|
||||
main_pids=$(pgrep -f "Electron\.app.*--remote-debugging-port=${CDP_PORT}" 2>/dev/null || true)
|
||||
[ -n "$main_pids" ] && pids="$pids $main_pids"
|
||||
# 1. Any process whose command line mentions this project's electron path
|
||||
# (covers the main Electron binary AND every Helper subprocess)
|
||||
local electron_pids
|
||||
electron_pids=$(pgrep -f "$PROJECT_ELECTRON_PATH" 2>/dev/null || true)
|
||||
pids="$pids $electron_pids"
|
||||
|
||||
# 2. Electron Helper processes (gpu, renderer, utility) spawned from the project's electron binary
|
||||
local helper_pids
|
||||
helper_pids=$(pgrep -f "${PROJECT_ROOT}/apps/desktop/node_modules/.*Electron Helper" 2>/dev/null || true)
|
||||
[ -n "$helper_pids" ] && pids="$pids $helper_pids"
|
||||
|
||||
# 3. electron-vite dev server
|
||||
# 2. electron-vite dev server (narrow match to avoid catching unrelated Vite invocations)
|
||||
local vite_pids
|
||||
vite_pids=$(pgrep -f "electron-vite.*dev" 2>/dev/null || true)
|
||||
[ -n "$vite_pids" ] && pids="$pids $vite_pids"
|
||||
vite_pids=$(pgrep -f "electron-vite[/.].*\\bdev\\b" 2>/dev/null || true)
|
||||
pids="$pids $vite_pids"
|
||||
|
||||
# 4. PID from pidfile (fallback)
|
||||
# 3. The launcher subshell from a previous `start` (saved to pidfile)
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
local saved_pid
|
||||
saved_pid=$(cat "$PIDFILE")
|
||||
if kill -0 "$saved_pid" 2>/dev/null; then
|
||||
saved_pid=$(cat "$PIDFILE" 2>/dev/null || true)
|
||||
if [ -n "$saved_pid" ] && kill -0 "$saved_pid" 2>/dev/null; then
|
||||
pids="$pids $saved_pid"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Deduplicate
|
||||
echo "$pids" | tr ' ' '\n' | sort -u | grep -v '^$' | tr '\n' ' ' || true
|
||||
# 4. Whatever is currently bound to the CDP port — catches strays whose
|
||||
# binary path doesn't match (e.g. orphaned from a crashed restart)
|
||||
local port_pid
|
||||
port_pid=$(lsof -ti tcp:"$CDP_PORT" -sTCP:LISTEN 2>/dev/null || true)
|
||||
pids="$pids $port_pid"
|
||||
|
||||
echo "$pids" | tr ' ' '\n' | sort -u | grep -v '^$' | tr '\n' ' '
|
||||
}
|
||||
|
||||
# Wait for the CDP HTTP endpoint to respond, with a deadline + early bail-out
|
||||
# if the launcher process died (no point waiting if Electron crashed).
|
||||
wait_for_cdp() {
|
||||
local deadline=$(( $(date +%s) + ELECTRON_WAIT_S ))
|
||||
echo "[electron-dev] Waiting for CDP on port ${CDP_PORT} (up to ${ELECTRON_WAIT_S}s)..."
|
||||
|
||||
while [ "$(date +%s)" -lt "$deadline" ]; do
|
||||
if curl -sf --max-time 2 "http://localhost:${CDP_PORT}/json/version" >/dev/null 2>&1; then
|
||||
echo "[electron-dev] CDP is reachable."
|
||||
return 0
|
||||
fi
|
||||
|
||||
# If our launcher subshell died, abort early so we don't hang the full timeout
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
local saved_pid
|
||||
saved_pid=$(cat "$PIDFILE" 2>/dev/null || true)
|
||||
if [ -n "$saved_pid" ] && ! kill -0 "$saved_pid" 2>/dev/null; then
|
||||
echo "[electron-dev] Launcher PID $saved_pid is gone before CDP came up."
|
||||
echo "[electron-dev] Last 30 lines of $ELECTRON_LOG:"
|
||||
tail -30 "$ELECTRON_LOG" 2>/dev/null || true
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "[electron-dev] ERROR: CDP did not respond within ${ELECTRON_WAIT_S}s"
|
||||
echo "[electron-dev] Last 30 lines of $ELECTRON_LOG:"
|
||||
tail -30 "$ELECTRON_LOG" 2>/dev/null || true
|
||||
return 1
|
||||
}
|
||||
|
||||
# After CDP is up, wait until the SPA renders interactive elements.
|
||||
wait_for_renderer() {
|
||||
local deadline=$(( $(date +%s) + RENDERER_WAIT_S ))
|
||||
echo "[electron-dev] Waiting for SPA to load (up to ${RENDERER_WAIT_S}s)..."
|
||||
|
||||
while [ "$(date +%s)" -lt "$deadline" ]; do
|
||||
local snap
|
||||
snap=$(agent-browser --cdp "$CDP_PORT" snapshot -i 2>&1 || true)
|
||||
if echo "$snap" | grep -qE '\b(link|button)\b'; then
|
||||
echo "[electron-dev] Renderer ready."
|
||||
return 0
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "[electron-dev] WARNING: Renderer not interactive within ${RENDERER_WAIT_S}s — proceeding anyway."
|
||||
return 0
|
||||
}
|
||||
|
||||
# ── Commands ─────────────────────────────────────────────────────────
|
||||
|
||||
do_stop() {
|
||||
echo "[electron-dev] Stopping Electron dev environment..."
|
||||
|
||||
local pids
|
||||
pids=$(find_electron_pids)
|
||||
local seed_pids
|
||||
seed_pids=$(find_project_pids)
|
||||
|
||||
if [ -z "$pids" ]; then
|
||||
echo "[electron-dev] No Electron processes found."
|
||||
# Expand to include all descendants — catches helpers spawned by the main
|
||||
# process AFTER our pgrep snapshot, and the launcher's child node/electron-vite
|
||||
# process tree.
|
||||
local all_pids=""
|
||||
for pid in $seed_pids; do
|
||||
all_pids="$all_pids $(expand_descendants "$pid")"
|
||||
done
|
||||
all_pids=$(echo "$all_pids" | tr ' ' '\n' | sort -u | grep -v '^$' | tr '\n' ' ')
|
||||
|
||||
if [ -z "$all_pids" ]; then
|
||||
echo "[electron-dev] No project Electron/vite processes found."
|
||||
else
|
||||
echo "[electron-dev] Killing PIDs: $pids"
|
||||
for pid in $pids; do
|
||||
local count
|
||||
count=$(echo "$all_pids" | tr ' ' '\n' | grep -c .)
|
||||
echo "[electron-dev] Sending SIGTERM to $count process(es): $all_pids"
|
||||
for pid in $all_pids; do
|
||||
kill "$pid" 2>/dev/null || true
|
||||
done
|
||||
|
||||
# Wait up to 5s for graceful exit, then force-kill survivors
|
||||
# Wait up to 5s for graceful exit
|
||||
local waited=0
|
||||
while [ $waited -lt 5 ]; do
|
||||
local alive=""
|
||||
for pid in $pids; do
|
||||
kill -0 "$pid" 2>/dev/null && alive="$alive $pid"
|
||||
local any_alive=0
|
||||
for pid in $all_pids; do
|
||||
if kill -0 "$pid" 2>/dev/null; then any_alive=1; break; fi
|
||||
done
|
||||
[ -z "$alive" ] && break
|
||||
[ "$any_alive" = "0" ] && break
|
||||
sleep 1
|
||||
waited=$((waited + 1))
|
||||
done
|
||||
|
||||
# Force-kill any remaining
|
||||
for pid in $pids; do
|
||||
# SIGKILL anyone still alive
|
||||
for pid in $all_pids; do
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
echo "[electron-dev] Force-killing PID $pid"
|
||||
kill -9 "$pid" 2>/dev/null || true
|
||||
@@ -98,7 +179,27 @@ do_stop() {
|
||||
done
|
||||
fi
|
||||
|
||||
# Also close any agent-browser sessions connected to this port
|
||||
# Belt-and-suspenders: anything still bound to the CDP port goes away
|
||||
local port_pid
|
||||
port_pid=$(lsof -ti tcp:"$CDP_PORT" -sTCP:LISTEN 2>/dev/null || true)
|
||||
if [ -n "$port_pid" ]; then
|
||||
echo "[electron-dev] Port $CDP_PORT still bound by PID $port_pid; force-killing"
|
||||
# shellcheck disable=SC2086
|
||||
kill -9 $port_pid 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Also re-sweep the project's electron processes — sometimes the OS spawns
|
||||
# new helpers during shutdown that didn't exist when we first enumerated.
|
||||
local stragglers
|
||||
stragglers=$(pgrep -f "$PROJECT_ELECTRON_PATH" 2>/dev/null || true)
|
||||
if [ -n "$stragglers" ]; then
|
||||
echo "[electron-dev] Cleaning up stragglers: $stragglers"
|
||||
for pid in $stragglers; do
|
||||
kill -9 "$pid" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
|
||||
# Close any agent-browser sessions connected to this port
|
||||
agent-browser --cdp "$CDP_PORT" close --all 2>/dev/null || true
|
||||
|
||||
rm -f "$PIDFILE"
|
||||
@@ -107,113 +208,84 @@ do_stop() {
|
||||
|
||||
do_status() {
|
||||
local pids
|
||||
pids=$(find_electron_pids)
|
||||
pids=$(find_project_pids)
|
||||
|
||||
if [ -z "$pids" ]; then
|
||||
echo "[electron-dev] Electron is NOT running."
|
||||
echo "[electron-dev] No project Electron processes found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "[electron-dev] Electron is running (PIDs: $pids)"
|
||||
echo "[electron-dev] Project processes: $pids"
|
||||
|
||||
# Check CDP connectivity
|
||||
if agent-browser --cdp "$CDP_PORT" get url >/dev/null 2>&1; then
|
||||
if curl -sf --max-time 2 "http://localhost:${CDP_PORT}/json/version" >/dev/null 2>&1; then
|
||||
local url
|
||||
url=$(agent-browser --cdp "$CDP_PORT" get url 2>&1 | tail -1)
|
||||
url=$(agent-browser --cdp "$CDP_PORT" get url 2>&1 | tail -1 || echo "?")
|
||||
echo "[electron-dev] CDP port ${CDP_PORT} is reachable. URL: $url"
|
||||
return 0
|
||||
else
|
||||
echo "[electron-dev] CDP port ${CDP_PORT} is NOT reachable (Electron may still be loading)."
|
||||
echo "[electron-dev] CDP port ${CDP_PORT} is NOT reachable (no --remote-debugging-port, or still loading)."
|
||||
return 2
|
||||
fi
|
||||
}
|
||||
|
||||
wait_for_electron() {
|
||||
echo "[electron-dev] Waiting for Electron process (up to ${ELECTRON_WAIT_S}s)..."
|
||||
local elapsed=0
|
||||
local interval=3
|
||||
while [ $elapsed -lt "$ELECTRON_WAIT_S" ]; do
|
||||
if strings "$ELECTRON_LOG" 2>/dev/null | grep -q "starting electron"; then
|
||||
echo "[electron-dev] Electron process started."
|
||||
return 0
|
||||
fi
|
||||
sleep "$interval"
|
||||
elapsed=$((elapsed + interval))
|
||||
echo "[electron-dev] Still waiting... (${elapsed}/${ELECTRON_WAIT_S}s)"
|
||||
done
|
||||
echo "[electron-dev] ERROR: Electron did not start within ${ELECTRON_WAIT_S}s"
|
||||
echo "[electron-dev] Last 20 lines of log:"
|
||||
tail -20 "$ELECTRON_LOG" 2>/dev/null || true
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_renderer() {
|
||||
echo "[electron-dev] Waiting for renderer/SPA to load (up to ${RENDERER_WAIT_S}s)..."
|
||||
|
||||
# Initial delay — renderer needs time to bootstrap
|
||||
sleep 10
|
||||
|
||||
local elapsed=10
|
||||
local interval=5
|
||||
while [ $elapsed -lt "$RENDERER_WAIT_S" ]; do
|
||||
if agent-browser --cdp "$CDP_PORT" wait 2000 >/dev/null 2>&1; then
|
||||
# Check if interactive elements are present (SPA loaded)
|
||||
local snap
|
||||
snap=$(agent-browser --cdp "$CDP_PORT" snapshot -i 2>&1 || true)
|
||||
if echo "$snap" | grep -qE 'link |button '; then
|
||||
echo "[electron-dev] Renderer ready (interactive elements found)."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
sleep "$interval"
|
||||
elapsed=$((elapsed + interval))
|
||||
echo "[electron-dev] SPA still loading... (${elapsed}/${RENDERER_WAIT_S}s)"
|
||||
done
|
||||
|
||||
echo "[electron-dev] WARNING: Timed out waiting for renderer, proceeding anyway."
|
||||
return 0
|
||||
}
|
||||
|
||||
do_start() {
|
||||
# If already running and healthy, skip
|
||||
local status_ok=0
|
||||
do_status >/dev/null 2>&1 || status_ok=$?
|
||||
if [ "$status_ok" -eq 0 ]; then
|
||||
echo "[electron-dev] Electron is already running and CDP is reachable. Skipping start."
|
||||
echo "[electron-dev] Use 'restart' to force a fresh session, or 'stop' to tear down."
|
||||
# Already up and CDP is reachable → nothing to do
|
||||
if curl -sf --max-time 2 "http://localhost:${CDP_PORT}/json/version" >/dev/null 2>&1; then
|
||||
echo "[electron-dev] CDP already reachable on port $CDP_PORT. Skipping start."
|
||||
echo "[electron-dev] Use 'restart' to force a fresh session."
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Clean up any stale processes
|
||||
# Detect the user's existing dev session (or stale processes) BEFORE killing
|
||||
local existing
|
||||
existing=$(find_project_pids)
|
||||
if [ -n "$existing" ]; then
|
||||
echo "[electron-dev] Existing project Electron/vite processes detected:"
|
||||
echo "$existing" | tr ' ' '\n' | sed 's/^/[electron-dev] PID /'
|
||||
echo "[electron-dev] Tearing them down so we can start a CDP-enabled session..."
|
||||
fi
|
||||
|
||||
do_stop
|
||||
|
||||
# Start fresh
|
||||
# Wait for port + user-data-dir locks to release. Without this, the new
|
||||
# Electron may fail with "user data directory in use" or fail to bind CDP.
|
||||
local waited=0
|
||||
while [ $waited -lt 10 ]; do
|
||||
if ! lsof -i tcp:"$CDP_PORT" >/dev/null 2>&1 \
|
||||
&& ! pgrep -f "$PROJECT_ELECTRON_PATH" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
[ $waited -eq 0 ] && echo "[electron-dev] Waiting for port + Electron locks to release..."
|
||||
sleep 1
|
||||
waited=$((waited + 1))
|
||||
done
|
||||
|
||||
echo "[electron-dev] Starting Electron dev server..."
|
||||
echo "[electron-dev] Project: $PROJECT_ROOT"
|
||||
echo "[electron-dev] Project: $PROJECT_ROOT"
|
||||
echo "[electron-dev] CDP port: $CDP_PORT"
|
||||
echo "[electron-dev] Log: $ELECTRON_LOG"
|
||||
echo "[electron-dev] Log: $ELECTRON_LOG"
|
||||
|
||||
: > "$ELECTRON_LOG" # Truncate log
|
||||
|
||||
(
|
||||
cd "$PROJECT_ROOT/apps/desktop" && \
|
||||
ELECTRON_ENABLE_LOGGING=1 npx electron-vite dev -- --remote-debugging-port="$CDP_PORT" \
|
||||
>> "$ELECTRON_LOG" 2>&1
|
||||
) &
|
||||
local bg_pid=$!
|
||||
echo "$bg_pid" > "$PIDFILE"
|
||||
echo "[electron-dev] Background PID: $bg_pid"
|
||||
# Launch in a new session (setsid) so the whole process tree shares a PGID
|
||||
# we can later signal in one shot. `setsid bash -c '... exec ...' &` keeps
|
||||
# the bash shell as the session leader; its PID is what we save.
|
||||
setsid bash -c "
|
||||
cd '$PROJECT_ROOT/apps/desktop'
|
||||
exec npx electron-vite dev -- --remote-debugging-port=$CDP_PORT
|
||||
" >> "$ELECTRON_LOG" 2>&1 < /dev/null &
|
||||
local launcher_pid=$!
|
||||
echo "$launcher_pid" > "$PIDFILE"
|
||||
echo "[electron-dev] Launcher PID (session leader): $launcher_pid"
|
||||
|
||||
# Wait for Electron process to start
|
||||
if ! wait_for_electron; then
|
||||
echo "[electron-dev] Failed to start. Cleaning up..."
|
||||
if ! wait_for_cdp; then
|
||||
echo "[electron-dev] Failed to bring up CDP. Cleaning up..."
|
||||
do_stop
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Wait for renderer to be interactive
|
||||
if ! wait_for_renderer; then
|
||||
echo "[electron-dev] Renderer not ready, but Electron is running. You may need to wait more."
|
||||
echo "[electron-dev] Renderer not interactive — you may need to wait more."
|
||||
fi
|
||||
|
||||
echo "[electron-dev] Ready! Use: agent-browser --cdp $CDP_PORT snapshot -i"
|
||||
@@ -221,7 +293,7 @@ do_start() {
|
||||
|
||||
do_restart() {
|
||||
do_stop
|
||||
sleep 2
|
||||
sleep 1
|
||||
do_start
|
||||
}
|
||||
|
||||
@@ -235,10 +307,12 @@ case "${1:-help}" in
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|status|restart}"
|
||||
echo ""
|
||||
echo " start — Start Electron dev with CDP (idempotent, skips if already running)"
|
||||
echo " stop — Kill all Electron dev processes (main + helpers + vite)"
|
||||
echo " status — Check if Electron is running and CDP is reachable"
|
||||
echo " restart — Stop then start"
|
||||
echo " start — Start Electron dev with CDP. Detects + tears down any"
|
||||
echo " existing project Electron (e.g. \`bun run dev\`) first."
|
||||
echo " stop — Kill all project Electron/vite processes (main + helpers"
|
||||
echo " + descendants), with SIGTERM → 5s wait → SIGKILL fallback."
|
||||
echo " status — Check if Electron is running and CDP is reachable."
|
||||
echo " restart — Stop then start."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
name: 'source-command-dedupe'
|
||||
description: 'Find duplicate GitHub issues'
|
||||
---
|
||||
|
||||
# source-command-dedupe
|
||||
|
||||
Use this skill when the user asks to run the migrated source command `dedupe`.
|
||||
|
||||
## Command Template
|
||||
|
||||
Find up to 3 likely duplicate issues for a given GitHub issue.
|
||||
|
||||
To do this, follow these steps precisely:
|
||||
|
||||
1. Use an agent to check if the Github issue (a) is closed, (b) does not need to be deduped (eg. because it is broad product feedback without a specific solution, or positive feedback), or (c) already has a duplicates comment that you made earlier. If so, do not proceed.
|
||||
2. Use an agent to view a Github issue, and ask the agent to return a summary of the issue
|
||||
3. Then, launch 5 parallel agents to search Github for duplicates of this issue, using diverse keywords and search approaches, using the summary from #1
|
||||
4. Next, feed the results from #1 and #2 into another agent, so that it can filter out false positives, that are likely not actually duplicates of the original issue. If there are no duplicates remaining, do not proceed.
|
||||
5. Finally, comment back on the issue with a list of up to three duplicate issues (or zero, if there are no likely duplicates)
|
||||
|
||||
Notes (be sure to tell this to your agents, too):
|
||||
|
||||
- Use `gh` to interact with Github, rather than web fetch
|
||||
- Do not use other tools, beyond `gh` (eg. don't use other MCP servers, file edit, etc.)
|
||||
- Make a todo list first
|
||||
- For your comment, follow the following format precisely (assuming for this example that you found 3 suspected duplicates):
|
||||
|
||||
---
|
||||
|
||||
Found 3 possible duplicate issues:
|
||||
|
||||
1. <link to issue>
|
||||
2. <link to issue>
|
||||
3. <link to issue>
|
||||
|
||||
This issue will be automatically closed as a duplicate in 3 days.
|
||||
|
||||
- If your issue is a duplicate, please close it and 👍 the existing issue instead
|
||||
- To prevent auto-closure, add a comment or 👎 this comment
|
||||
|
||||
> 🤖 Generated with Codex
|
||||
|
||||
---
|
||||
@@ -189,7 +189,7 @@ If metrics cannot be reliably computed, omit unknown numbers instead of guessing
|
||||
|
||||
Follow this section order unless the user asks otherwise:
|
||||
|
||||
1. `# 🚀 LobeHub v<x.y.z> (<YYYYMMDD>)`
|
||||
1. `# 🚀 LobeHub Release (<YYYYMMDD>)`
|
||||
2. Metadata lines:
|
||||
- `Release Date`
|
||||
- `Since <Previous Version>` metrics
|
||||
@@ -262,7 +262,7 @@ If a new contributor appears who is not on this list, treat them as community by
|
||||
### GitHub Release Changelog Template
|
||||
|
||||
```md
|
||||
# 🚀 LobeHub v<x.y.z> (<YYYYMMDD>)
|
||||
# 🚀 LobeHub Release (<YYYYMMDD>)
|
||||
|
||||
**Release Date:** <Month DD, YYYY>
|
||||
**Since <Previous Version>:** <N merged PRs> · <N resolved issues> · <N contributors>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 🚀 LobeHub v2.1.50 (20260416)
|
||||
# 🚀 LobeHub Release (20260416)
|
||||
|
||||
**Release Date:** April 20, 2026\
|
||||
**Migration Scope:** Agent benchmark data model bootstrap (5 new tables, 2 new indexes)
|
||||
@@ -7,14 +7,6 @@
|
||||
|
||||
---
|
||||
|
||||
## ✨ Highlights
|
||||
|
||||
- **Benchmark Lifecycle Schema** — Added a relational model that tracks benchmark setup, runs, per-topic execution, and record outputs end-to-end.
|
||||
- **Queryability Upgrade** — Added indexes for run status and benchmark-topic joins, improving operational queries in dashboard and debugging workflows.
|
||||
- **Safer Operator Rollout** — Migration is startup-driven and backward-compatible with existing non-benchmark chat workflows.
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Migration Overview
|
||||
|
||||
Added tables:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 🚀 LobeHub v2.1.54 (20260427)
|
||||
# 🚀 LobeHub Release (20260427)
|
||||
|
||||
**Hotfix Scope:** Agent topic-switching regression — stale chat state on agent change
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 🚀 LobeHub v2.1.50 (20260420)
|
||||
# 🚀 LobeHub Release (20260420)
|
||||
|
||||
**Release Date:** April 20, 2026\
|
||||
**Since v2026.04.13:** 96 commits · 58 merged PRs · 31 resolved issues · 17 contributors
|
||||
**Since previous release:** 96 commits · 58 merged PRs · 31 resolved issues · 17 contributors
|
||||
|
||||
> This weekly release focuses on reducing friction in everyday agent work: faster model routing, smoother gateway behavior, stronger task continuity, and clearer operator diagnostics when something goes wrong.
|
||||
|
||||
@@ -77,4 +77,4 @@
|
||||
|
||||
---
|
||||
|
||||
**Full Changelog**: v2026.04.13...v2026.04.20
|
||||
**Full Changelog**: <previous-tag>...<current-tag>
|
||||
|
||||
@@ -174,9 +174,64 @@ export const chatGroupAction: StateCreator<
|
||||
- `ChatGroupStoreWithRefresh` for member refresh
|
||||
- `ChatGroupStoreWithInternal` for curd `internal_dispatchChatGroup`
|
||||
|
||||
### Slices That Don't Currently Need `set`
|
||||
|
||||
When a slice doesn't write local state at the moment — e.g. it reads context
|
||||
from `#get()` and forwards calls to another store, or just runs hooks — drop
|
||||
the `#set` field. Otherwise ESLint's `no-unused-vars` flags the unused private
|
||||
field.
|
||||
|
||||
Mark the constructor's `set` param as `_set` and `void _set` it to keep the
|
||||
`(set, get, api)` shape aligned with `StateCreator`. This is **a snapshot of
|
||||
the current need, not a permanent contract** — if a later change needs `set`,
|
||||
restore the `#set` field and use it; do not invent a workaround to keep the
|
||||
"unused" form.
|
||||
|
||||
```ts
|
||||
type Setter = StoreSetter<ConversationStore>;
|
||||
|
||||
export const toolSlice = (set: Setter, get: () => ConversationStore, _api?: unknown) =>
|
||||
new ToolActionImpl(set, get, _api);
|
||||
|
||||
export class ToolActionImpl {
|
||||
readonly #get: () => ConversationStore;
|
||||
|
||||
// Mark unused params with `_` prefix and `void _x` so the constructor still
|
||||
// matches StateCreator's `(set, get, api)` shape without triggering unused
|
||||
// diagnostics.
|
||||
constructor(_set: Setter, get: () => ConversationStore, _api?: unknown) {
|
||||
void _set;
|
||||
void _api;
|
||||
this.#get = get;
|
||||
}
|
||||
|
||||
approveToolCall = async (id: string) => {
|
||||
const { context, hooks } = this.#get();
|
||||
await useChatStore.getState().approveToolCalling(id, '', context);
|
||||
hooks.onToolCallComplete?.(id, undefined);
|
||||
};
|
||||
}
|
||||
|
||||
export type ToolAction = Pick<ToolActionImpl, keyof ToolActionImpl>;
|
||||
```
|
||||
|
||||
Rules of thumb:
|
||||
|
||||
- If a slice doesn't currently call `set`, drop `#set` (use `_set` + `void _set`
|
||||
in the constructor). When a later edit needs `set`, restore `#set` and use it.
|
||||
- Don't add `setNamespace` for slices that don't write state. Add it when the
|
||||
slice starts writing state.
|
||||
- Never leave `#set` declared but unused "for future use" — lint will fail and
|
||||
re-adding it later costs nothing.
|
||||
|
||||
### Do / Don't
|
||||
|
||||
- **Do**: keep constructor signature aligned with `StateCreator` params `(set, get, api)`.
|
||||
- **Do**: use `#private` to avoid `set/get` being exposed.
|
||||
- **Do**: use `flattenActions` instead of spreading class instances.
|
||||
- **Do**: drop `#set` (and use `_set` + `void _set` in the constructor) for
|
||||
delegate-only slices that never write state — keeps lint green without
|
||||
breaking the `(set, get, api)` shape.
|
||||
- **Don't**: keep both old slice objects and class actions active at the same time.
|
||||
- **Don't**: keep an unused `#set` field "for future use" — it fails ESLint and
|
||||
re-adding it later costs nothing.
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
name: Test Packages
|
||||
env:
|
||||
PACKAGES: '@lobechat/file-loaders @lobechat/prompts @lobechat/model-runtime @lobechat/web-crawler @lobechat/electron-server-ipc @lobechat/utils @lobechat/python-interpreter @lobechat/context-engine @lobechat/agent-runtime @lobechat/conversation-flow @lobechat/ssrf-safe-fetch @lobechat/memory-user-memory model-bank'
|
||||
PACKAGES: '@lobechat/file-loaders @lobechat/prompts @lobechat/model-runtime @lobechat/web-crawler @lobechat/electron-server-ipc @lobechat/utils @lobechat/python-interpreter @lobechat/context-engine @lobechat/agent-runtime @lobechat/conversation-flow @lobechat/ssrf-safe-fetch @lobechat/memory-user-memory @lobechat/types @lobechat/builtin-tool-lobe-agent model-bank'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
@@ -2,6 +2,31 @@
|
||||
|
||||
# Changelog
|
||||
|
||||
### [Version 2.1.56](https://github.com/lobehub/lobe-chat/compare/v2.1.55...v2.1.56)
|
||||
|
||||
<sup>Released on **2026-05-01**</sup>
|
||||
|
||||
#### 👷 Build System
|
||||
|
||||
- **database**: add `metadata` and `trigger` to `briefs` table.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### Build System
|
||||
|
||||
- **database**: add `metadata` and `trigger` to `briefs` table, closes [#14354](https://github.com/lobehub/lobe-chat/issues/14354) ([86a23b5](https://github.com/lobehub/lobe-chat/commit/86a23b5))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 2.1.55](https://github.com/lobehub/lobe-chat/compare/v2.1.54...v2.1.55)
|
||||
|
||||
<sup>Released on **2026-04-29**</sup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" 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.8" "User Commands"
|
||||
.TH LH 1 "" "@lobehub/cli 0.0.11" "User Commands"
|
||||
.SH NAME
|
||||
lh \- LobeHub CLI \- manage and connect to LobeHub services
|
||||
.SH SYNOPSIS
|
||||
@@ -77,6 +77,9 @@ Generate content (text, image, video, speech) Alias: gen.
|
||||
.B file
|
||||
Manage files
|
||||
.TP
|
||||
.B hetero
|
||||
Run heterogeneous agent CLIs (Claude Code / Codex) and stream their output
|
||||
.TP
|
||||
.B skill
|
||||
Manage agent skills
|
||||
.TP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@lobehub/cli",
|
||||
"version": "0.0.8",
|
||||
"version": "0.0.11",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"lh": "./dist/index.js",
|
||||
@@ -30,6 +30,7 @@
|
||||
"devDependencies": {
|
||||
"@lobechat/agent-gateway-client": "workspace:*",
|
||||
"@lobechat/device-gateway-client": "workspace:*",
|
||||
"@lobechat/heterogeneous-agents": "workspace:*",
|
||||
"@lobechat/local-file-shell": "workspace:*",
|
||||
"@trpc/client": "^11.8.1",
|
||||
"@types/node": "^22.13.5",
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
packages:
|
||||
- '../../packages/agent-gateway-client'
|
||||
- '../../packages/device-gateway-client'
|
||||
- '../../packages/heterogeneous-agents'
|
||||
- '../../packages/local-file-shell'
|
||||
- '../../packages/types'
|
||||
- '../../packages/model-bank'
|
||||
- '../../packages/business/const'
|
||||
- '../../packages/file-loaders'
|
||||
- '.'
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
import { PassThrough } from 'node:stream';
|
||||
|
||||
import { Command } from 'commander';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { registerHeteroCommand } from './hetero';
|
||||
|
||||
const { mockSpawnAgent } = vi.hoisted(() => ({
|
||||
mockSpawnAgent: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@lobechat/heterogeneous-agents/spawn', () => ({
|
||||
spawnAgent: mockSpawnAgent,
|
||||
}));
|
||||
|
||||
vi.mock('../utils/logger', () => ({
|
||||
log: { debug: vi.fn(), error: vi.fn(), info: vi.fn(), warn: vi.fn() },
|
||||
setVerbose: vi.fn(),
|
||||
}));
|
||||
|
||||
/**
|
||||
* Build a Promise resolving to a fake `SpawnAgentHandle`. `spawnAgent` itself
|
||||
* is async, so test mocks return the handle wrapped — same iterable contract,
|
||||
* just behind one microtask. The async iterable yields `events` synchronously
|
||||
* and ends, so the command's `for await (const event of ...)` loop terminates
|
||||
* without hanging the test.
|
||||
*/
|
||||
const createFakeHandle = ({
|
||||
events = [] as any[],
|
||||
exitCode = 0,
|
||||
signal = null as NodeJS.Signals | null,
|
||||
stderrChunks = [] as string[],
|
||||
}: {
|
||||
events?: any[];
|
||||
exitCode?: number | null;
|
||||
signal?: NodeJS.Signals | null;
|
||||
stderrChunks?: string[];
|
||||
} = {}) => {
|
||||
const stderr = new PassThrough();
|
||||
setImmediate(() => {
|
||||
for (const c of stderrChunks) stderr.write(c);
|
||||
stderr.end();
|
||||
});
|
||||
|
||||
const eventsIter: AsyncIterable<any> = {
|
||||
[Symbol.asyncIterator]() {
|
||||
let i = 0;
|
||||
return {
|
||||
async next() {
|
||||
if (i < events.length) return { done: false, value: events[i++] };
|
||||
return { done: true, value: undefined };
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
return Promise.resolve({
|
||||
events: eventsIter,
|
||||
exit: Promise.resolve({ code: exitCode, signal }),
|
||||
kill: vi.fn(),
|
||||
pid: 12_345,
|
||||
stderr,
|
||||
});
|
||||
};
|
||||
|
||||
describe('hetero exec command', () => {
|
||||
let exitSpy: ReturnType<typeof vi.spyOn>;
|
||||
let stdoutSpy: ReturnType<typeof vi.spyOn>;
|
||||
|
||||
beforeEach(() => {
|
||||
// Stub `process.exit` so the test runner doesn't tear down — but THROW a
|
||||
// sentinel rather than return, mirroring `process.exit`'s `never` return
|
||||
// type in production. Without throwing, the command's code after an
|
||||
// `exit(2)` keeps running and crashes on `handle.stderr` (no spawn mock).
|
||||
exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code?: number) => {
|
||||
throw new Error(`__exit__${code}`);
|
||||
}) as any);
|
||||
stdoutSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
||||
mockSpawnAgent.mockReset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
exitSpy.mockRestore();
|
||||
stdoutSpy.mockRestore();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
/** Build a fresh program with the hetero command registered. */
|
||||
const buildProgram = () => {
|
||||
const program = new Command();
|
||||
program.exitOverride();
|
||||
registerHeteroCommand(program);
|
||||
return program;
|
||||
};
|
||||
|
||||
/**
|
||||
* Run the parsed command. Swallows our `__exit__<code>` sentinel so tests
|
||||
* can inspect `exitSpy.mock.calls` afterwards instead of having to wrap
|
||||
* every `parseAsync` in `expect(...).rejects`. Real production exits stay
|
||||
* `process.exit` so this only affects the test path.
|
||||
*/
|
||||
const runCmd = async (argv: string[]) => {
|
||||
try {
|
||||
await buildProgram().parseAsync(argv, { from: 'user' });
|
||||
} catch (err) {
|
||||
if (err instanceof Error && err.message.startsWith('__exit__')) return;
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
it('rejects unsupported agent types via process.exit(2)', async () => {
|
||||
await runCmd(['hetero', 'exec', '--type', 'kimi-cli', '--prompt', 'hi']);
|
||||
expect(exitSpy).toHaveBeenCalledWith(2);
|
||||
expect(mockSpawnAgent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('rejects empty prompts via process.exit(2)', async () => {
|
||||
await runCmd(['hetero', 'exec', '--type', 'claude-code', '--prompt', ' ']);
|
||||
expect(exitSpy).toHaveBeenCalledWith(2);
|
||||
expect(mockSpawnAgent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('passes --type / --prompt / --resume / --cwd / --command through to spawnAgent', async () => {
|
||||
mockSpawnAgent.mockReturnValue(createFakeHandle());
|
||||
|
||||
await runCmd([
|
||||
'hetero',
|
||||
'exec',
|
||||
'--type',
|
||||
'codex',
|
||||
'--prompt',
|
||||
'do thing',
|
||||
'--resume',
|
||||
'thread_abc',
|
||||
'--cwd',
|
||||
'/tmp/work',
|
||||
'--command',
|
||||
'/usr/local/bin/codex',
|
||||
]);
|
||||
|
||||
expect(mockSpawnAgent).toHaveBeenCalledTimes(1);
|
||||
const call = mockSpawnAgent.mock.calls[0][0];
|
||||
expect(call).toMatchObject({
|
||||
agentType: 'codex',
|
||||
command: '/usr/local/bin/codex',
|
||||
cwd: '/tmp/work',
|
||||
prompt: 'do thing',
|
||||
resumeSessionId: 'thread_abc',
|
||||
});
|
||||
// operationId auto-generated when omitted (uuid v4 shape)
|
||||
expect(call.operationId).toMatch(/^[0-9a-f-]{36}$/i);
|
||||
});
|
||||
|
||||
it('uses the provided --operation-id verbatim', async () => {
|
||||
mockSpawnAgent.mockReturnValue(createFakeHandle());
|
||||
|
||||
await runCmd([
|
||||
'hetero',
|
||||
'exec',
|
||||
'--type',
|
||||
'claude-code',
|
||||
'--prompt',
|
||||
'hi',
|
||||
'--operation-id',
|
||||
'op-server-allocated',
|
||||
]);
|
||||
|
||||
const call = mockSpawnAgent.mock.calls[0][0];
|
||||
expect(call.operationId).toBe('op-server-allocated');
|
||||
});
|
||||
|
||||
it('streams events to stdout as JSONL, one line per event', async () => {
|
||||
const events = [
|
||||
{ data: { foo: 1 }, operationId: 'op-1', stepIndex: 0, timestamp: 1, type: 'stream_start' },
|
||||
{
|
||||
data: { chunkType: 'text', content: 'hi' },
|
||||
operationId: 'op-1',
|
||||
stepIndex: 0,
|
||||
timestamp: 2,
|
||||
type: 'stream_chunk',
|
||||
},
|
||||
];
|
||||
mockSpawnAgent.mockReturnValue(createFakeHandle({ events }));
|
||||
|
||||
await runCmd([
|
||||
'hetero',
|
||||
'exec',
|
||||
'--type',
|
||||
'claude-code',
|
||||
'--prompt',
|
||||
'hi',
|
||||
'--operation-id',
|
||||
'op-1',
|
||||
]);
|
||||
|
||||
// Each event is one JSON line with a trailing \n.
|
||||
const lines = stdoutSpy.mock.calls.map((c) => c[0]).filter((s) => typeof s === 'string');
|
||||
expect(lines).toHaveLength(2);
|
||||
for (const line of lines as string[]) {
|
||||
expect(line.endsWith('\n')).toBe(true);
|
||||
const parsed = JSON.parse(line);
|
||||
expect(parsed.operationId).toBe('op-1');
|
||||
}
|
||||
});
|
||||
|
||||
it('passes the child exit code straight through', async () => {
|
||||
mockSpawnAgent.mockReturnValue(createFakeHandle({ exitCode: 7 }));
|
||||
|
||||
await runCmd(['hetero', 'exec', '--type', 'claude-code', '--prompt', 'hi']);
|
||||
expect(exitSpy).toHaveBeenCalledWith(7);
|
||||
});
|
||||
|
||||
it('maps SIGINT (code === null) to POSIX exit code 130', async () => {
|
||||
mockSpawnAgent.mockReturnValue(createFakeHandle({ exitCode: null, signal: 'SIGINT' }));
|
||||
|
||||
await runCmd(['hetero', 'exec', '--type', 'claude-code', '--prompt', 'hi']);
|
||||
expect(exitSpy).toHaveBeenCalledWith(130);
|
||||
});
|
||||
|
||||
it('combines --prompt + --image into mixed content blocks', async () => {
|
||||
mockSpawnAgent.mockReturnValue(createFakeHandle());
|
||||
|
||||
await runCmd([
|
||||
'hetero',
|
||||
'exec',
|
||||
'--type',
|
||||
'claude-code',
|
||||
'--prompt',
|
||||
'describe',
|
||||
'--image',
|
||||
'./fixture-a.png',
|
||||
'--image',
|
||||
'https://cdn.example/fixture-b.png',
|
||||
]);
|
||||
|
||||
const call = mockSpawnAgent.mock.calls[0][0];
|
||||
expect(Array.isArray(call.prompt)).toBe(true);
|
||||
expect(call.prompt).toEqual([
|
||||
{ text: 'describe', type: 'text' },
|
||||
// Path is resolved against process.cwd() — match by suffix to be CI-portable.
|
||||
{
|
||||
source: expect.objectContaining({ type: 'path' }),
|
||||
type: 'image',
|
||||
},
|
||||
{
|
||||
source: { type: 'url', url: 'https://cdn.example/fixture-b.png' },
|
||||
type: 'image',
|
||||
},
|
||||
]);
|
||||
expect(call.prompt[1].source.path).toMatch(/fixture-a\.png$/);
|
||||
});
|
||||
|
||||
it('parses a data: URL --image into a base64 source', async () => {
|
||||
mockSpawnAgent.mockReturnValue(createFakeHandle());
|
||||
|
||||
const dataUrl = `data:image/png;base64,${Buffer.from([0x89, 0x50, 0x4e, 0x47]).toString('base64')}`;
|
||||
await runCmd([
|
||||
'hetero',
|
||||
'exec',
|
||||
'--type',
|
||||
'claude-code',
|
||||
'--prompt',
|
||||
'see',
|
||||
'--image',
|
||||
dataUrl,
|
||||
]);
|
||||
|
||||
const call = mockSpawnAgent.mock.calls[0][0];
|
||||
expect(call.prompt[1]).toEqual({
|
||||
source: {
|
||||
data: Buffer.from([0x89, 0x50, 0x4e, 0x47]).toString('base64'),
|
||||
mediaType: 'image/png',
|
||||
type: 'base64',
|
||||
},
|
||||
type: 'image',
|
||||
});
|
||||
});
|
||||
|
||||
it('reads multimodal content from --input-json <file>', async () => {
|
||||
const { mkdtemp, writeFile, rm } = await import('node:fs/promises');
|
||||
const { tmpdir } = await import('node:os');
|
||||
const path = await import('node:path');
|
||||
const dir = await mkdtemp(`${tmpdir()}/hetero-input-json-`);
|
||||
const file = path.join(dir, 'input.json');
|
||||
await writeFile(
|
||||
file,
|
||||
JSON.stringify([
|
||||
{ text: 'analyze', type: 'text' },
|
||||
{ source: { type: 'url', url: 'https://x/y.png' }, type: 'image' },
|
||||
]),
|
||||
);
|
||||
|
||||
mockSpawnAgent.mockReturnValue(createFakeHandle());
|
||||
try {
|
||||
await runCmd(['hetero', 'exec', '--type', 'claude-code', '--input-json', file]);
|
||||
} finally {
|
||||
await rm(dir, { force: true, recursive: true });
|
||||
}
|
||||
|
||||
const call = mockSpawnAgent.mock.calls[0][0];
|
||||
expect(call.prompt).toEqual([
|
||||
{ text: 'analyze', type: 'text' },
|
||||
{ source: { type: 'url', url: 'https://x/y.png' }, type: 'image' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('reports spawnAgent rejections (e.g. missing --image path) as a clean error + exit(1)', async () => {
|
||||
// spawnAgent is now async and can reject during image normalization —
|
||||
// missing local --image paths, fetch failures, etc. The CLI must catch
|
||||
// these and exit with a friendly message instead of crashing on an
|
||||
// unhandled rejection.
|
||||
mockSpawnAgent.mockReturnValue(
|
||||
Promise.reject(new Error('ENOENT: no such file or directory, open /missing.png')),
|
||||
);
|
||||
|
||||
await runCmd([
|
||||
'hetero',
|
||||
'exec',
|
||||
'--type',
|
||||
'claude-code',
|
||||
'--prompt',
|
||||
'see',
|
||||
'--image',
|
||||
'/missing.png',
|
||||
]);
|
||||
|
||||
expect(exitSpy).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it('rejects --prompt + --input-json (mutually exclusive)', async () => {
|
||||
await runCmd([
|
||||
'hetero',
|
||||
'exec',
|
||||
'--type',
|
||||
'claude-code',
|
||||
'--prompt',
|
||||
'hi',
|
||||
'--input-json',
|
||||
'/tmp/bogus.json',
|
||||
]);
|
||||
expect(exitSpy).toHaveBeenCalledWith(2);
|
||||
expect(mockSpawnAgent).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,274 @@
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
|
||||
import type {
|
||||
AgentContentBlock,
|
||||
AgentImageSource,
|
||||
AgentPromptInput,
|
||||
} from '@lobechat/heterogeneous-agents/spawn';
|
||||
import { spawnAgent } from '@lobechat/heterogeneous-agents/spawn';
|
||||
import type { Command } from 'commander';
|
||||
|
||||
import { log } from '../utils/logger';
|
||||
|
||||
const SUPPORTED_AGENT_TYPES = new Set(['claude-code', 'codex']);
|
||||
|
||||
interface ExecOptions {
|
||||
command?: string;
|
||||
cwd?: string;
|
||||
image?: string[];
|
||||
inputJson?: string;
|
||||
operationId?: string;
|
||||
prompt?: string;
|
||||
resume?: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
const collectImage = (value: string, previous: string[] = []): string[] => [...previous, value];
|
||||
|
||||
const readStdin = async (): Promise<string> => {
|
||||
const chunks: Buffer[] = [];
|
||||
for await (const chunk of process.stdin) {
|
||||
chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : (chunk as Buffer));
|
||||
}
|
||||
return Buffer.concat(chunks).toString('utf8');
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve a raw `--input-json` argument: `'-'` (or empty) reads stdin, anything
|
||||
* else is treated as a filesystem path.
|
||||
*/
|
||||
const readInputJson = async (location: string): Promise<string> => {
|
||||
if (location === '-' || location === '') return readStdin();
|
||||
return readFile(location, 'utf8');
|
||||
};
|
||||
|
||||
const looksLikeJsonInput = (value: string): boolean => {
|
||||
const trimmed = value.trimStart();
|
||||
return trimmed.startsWith('{') || trimmed.startsWith('[');
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert an `--image <value>` argument into an image source. Recognized
|
||||
* shapes: `https?://...` URL, `data:` URL, otherwise a filesystem path
|
||||
* resolved relative to the CLI's cwd.
|
||||
*/
|
||||
const parseImageArg = (value: string): AgentImageSource => {
|
||||
if (/^https?:\/\//i.test(value)) return { type: 'url', url: value };
|
||||
if (value.startsWith('data:')) {
|
||||
const match = value.match(/^data:([^;,]+);base64,(.+)$/);
|
||||
if (!match) {
|
||||
throw new Error(`Invalid data URL for --image: ${value.slice(0, 40)}…`);
|
||||
}
|
||||
return { data: match[2]!, mediaType: match[1]!, type: 'base64' };
|
||||
}
|
||||
return { path: path.resolve(process.cwd(), value), type: 'path' };
|
||||
};
|
||||
|
||||
/**
|
||||
* Best-effort coercion of a JSON-decoded value into an `AgentPromptInput`.
|
||||
* Accepts:
|
||||
* - `'plain text'` → single text block
|
||||
* - `[{ type: 'text', text }, { type: 'image', source }]` → content blocks
|
||||
* - `{ content: [...] }` (Anthropic message shape) → unwraps `content`
|
||||
* - `{ type: 'text', ... } | { type: 'image', ... }` → single block
|
||||
*/
|
||||
const coerceJsonPrompt = (parsed: unknown): AgentPromptInput => {
|
||||
if (typeof parsed === 'string') return parsed;
|
||||
if (Array.isArray(parsed)) return parsed as AgentContentBlock[];
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
const obj = parsed as Record<string, unknown>;
|
||||
if (Array.isArray(obj.content)) return obj.content as AgentContentBlock[];
|
||||
if (obj.type === 'text' || obj.type === 'image') return [obj as AgentContentBlock];
|
||||
}
|
||||
throw new Error(
|
||||
'Invalid --input-json shape: expected a string, array of content blocks, ' +
|
||||
'or `{ content: [...] }` envelope.',
|
||||
);
|
||||
};
|
||||
|
||||
interface ResolvedPrompt {
|
||||
/** Human-readable description for the empty-input check. */
|
||||
describe: () => string;
|
||||
prompt: AgentPromptInput;
|
||||
}
|
||||
|
||||
const buildPromptFromText = (text: string, images: string[]): ResolvedPrompt => {
|
||||
if (images.length === 0) {
|
||||
return { describe: () => text.trim(), prompt: text };
|
||||
}
|
||||
const blocks: AgentContentBlock[] = [];
|
||||
if (text.length > 0) blocks.push({ text, type: 'text' });
|
||||
for (const image of images) {
|
||||
blocks.push({ source: parseImageArg(image), type: 'image' });
|
||||
}
|
||||
return {
|
||||
describe: () =>
|
||||
blocks
|
||||
.map((b) => (b.type === 'text' ? b.text.trim() : '[image]'))
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
.trim(),
|
||||
prompt: blocks,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Decide which input mode the user requested and produce a unified prompt.
|
||||
*
|
||||
* Mode resolution (mutually exclusive):
|
||||
* 1. `--input-json` → read JSON file or stdin, parse to content blocks
|
||||
* 2. `--prompt` (with optional `--image` flags) → text + images
|
||||
* 3. (default) read stdin: auto-detect JSON vs plain text by first char
|
||||
*/
|
||||
const resolvePrompt = async (options: ExecOptions): Promise<ResolvedPrompt> => {
|
||||
const images = options.image ?? [];
|
||||
|
||||
if (options.inputJson !== undefined) {
|
||||
if (options.prompt !== undefined) {
|
||||
throw new Error('--prompt and --input-json are mutually exclusive.');
|
||||
}
|
||||
if (images.length > 0) {
|
||||
throw new Error('--image cannot be combined with --input-json (put images in the JSON).');
|
||||
}
|
||||
const raw = await readInputJson(options.inputJson);
|
||||
return { describe: () => raw.trim(), prompt: coerceJsonPrompt(JSON.parse(raw)) };
|
||||
}
|
||||
|
||||
if (options.prompt !== undefined && options.prompt !== '-') {
|
||||
return buildPromptFromText(options.prompt, images);
|
||||
}
|
||||
|
||||
// No --prompt or --prompt -: read stdin and auto-detect.
|
||||
const raw = await readStdin();
|
||||
if (looksLikeJsonInput(raw)) {
|
||||
return { describe: () => raw.trim(), prompt: coerceJsonPrompt(JSON.parse(raw)) };
|
||||
}
|
||||
return buildPromptFromText(raw, images);
|
||||
};
|
||||
|
||||
const exec = async (options: ExecOptions): Promise<void> => {
|
||||
if (!SUPPORTED_AGENT_TYPES.has(options.type)) {
|
||||
log.error(
|
||||
`Unsupported --type "${options.type}". Supported: ${[...SUPPORTED_AGENT_TYPES].join(', ')}`,
|
||||
);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
let resolved: ResolvedPrompt;
|
||||
try {
|
||||
resolved = await resolvePrompt(options);
|
||||
} catch (err) {
|
||||
log.error(err instanceof Error ? err.message : String(err));
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
if (!resolved.describe()) {
|
||||
log.error(
|
||||
'Empty prompt. Pass --prompt <text>, --image <path>, --input-json <file|->, or pipe content via stdin.',
|
||||
);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
// Standalone (phase 1a): no server ingest, so the operationId is just an
|
||||
// identity stamp on the JSONL stream. Generate a fresh one if the caller
|
||||
// didn't provide --operation-id; phase 1b will require it as a real
|
||||
// server-allocated id.
|
||||
const operationId = options.operationId || randomUUID();
|
||||
|
||||
// `spawnAgent` is async and can reject DURING image normalization — fetch
|
||||
// failures, missing local --image paths, decode errors. Surface those as a
|
||||
// clean error + exit code instead of an unhandled promise rejection / stack
|
||||
// trace, mirroring the validation try/catch above.
|
||||
let handle: Awaited<ReturnType<typeof spawnAgent>>;
|
||||
try {
|
||||
handle = await spawnAgent({
|
||||
agentType: options.type,
|
||||
command: options.command,
|
||||
cwd: options.cwd || process.cwd(),
|
||||
operationId,
|
||||
prompt: resolved.prompt,
|
||||
resumeSessionId: options.resume,
|
||||
});
|
||||
} catch (err) {
|
||||
log.error('Failed to start agent:', err instanceof Error ? err.message : String(err));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Forward the child's stderr to ours so users see CLI errors / warnings
|
||||
// (auth prompts, missing-binary errors, etc.) in the terminal.
|
||||
handle.stderr.pipe(process.stderr);
|
||||
|
||||
// Ctrl-C → SIGINT to the child's process group so the spawned CLI gets a
|
||||
// chance to clean up. Repeated Ctrl-C escalates to SIGKILL via the
|
||||
// standard "double-tap" pattern most CLIs implement themselves.
|
||||
let interrupted = false;
|
||||
const onSigint = () => {
|
||||
if (interrupted) {
|
||||
handle.kill('SIGKILL');
|
||||
return;
|
||||
}
|
||||
interrupted = true;
|
||||
handle.kill('SIGINT');
|
||||
};
|
||||
process.on('SIGINT', onSigint);
|
||||
process.on('SIGTERM', () => handle.kill('SIGTERM'));
|
||||
|
||||
// Stream events out as JSONL on stdout. Each line is one `AgentStreamEvent`.
|
||||
// Use raw write (not console.log) so we don't pull in console formatting
|
||||
// and JSONL stays parseable downstream.
|
||||
try {
|
||||
for await (const event of handle.events) {
|
||||
process.stdout.write(`${JSON.stringify(event)}\n`);
|
||||
}
|
||||
} catch (err) {
|
||||
log.error('Stream error from agent process:', err instanceof Error ? err.message : String(err));
|
||||
process.exit(1);
|
||||
} finally {
|
||||
process.off('SIGINT', onSigint);
|
||||
}
|
||||
|
||||
// Pass the child's exit code through. Signal-induced exits (SIGINT etc.)
|
||||
// surface as `code === null` — map to 130 (POSIX convention for SIGINT).
|
||||
const { code, signal } = await handle.exit;
|
||||
if (code !== null) process.exit(code);
|
||||
if (signal === 'SIGINT') process.exit(130);
|
||||
if (signal === 'SIGTERM') process.exit(143);
|
||||
if (signal === 'SIGKILL') process.exit(137);
|
||||
process.exit(1);
|
||||
};
|
||||
|
||||
export function registerHeteroCommand(program: Command) {
|
||||
const hetero = program
|
||||
.command('hetero')
|
||||
.description('Run heterogeneous agent CLIs (Claude Code / Codex) and stream their output');
|
||||
|
||||
hetero
|
||||
.command('exec')
|
||||
.description(
|
||||
'Spawn a heterogeneous agent CLI and stream its events as JSONL on stdout. Standalone mode (no server ingest).',
|
||||
)
|
||||
.requiredOption('-t, --type <type>', `Agent type: ${[...SUPPORTED_AGENT_TYPES].join(' | ')}`)
|
||||
.option('-p, --prompt [text]', 'Prompt text. Pass `-` (or omit the value) to read from stdin.')
|
||||
.option(
|
||||
'-i, --image <path|url>',
|
||||
'Attach an image (repeatable). Accepts a local path, http(s) URL, or data: URL.',
|
||||
collectImage,
|
||||
)
|
||||
.option(
|
||||
'--input-json <path>',
|
||||
'Read full multimodal prompt as JSON content blocks from a file. Use `-` for stdin.',
|
||||
)
|
||||
.option('-r, --resume <sessionId>', 'Resume an existing agent session by its native id')
|
||||
.option('-d, --cwd <path>', 'Working directory for the spawned agent (default: process.cwd())')
|
||||
.option(
|
||||
'-c, --command <bin>',
|
||||
'Override the agent CLI binary name (default: `claude` or `codex`)',
|
||||
)
|
||||
.option(
|
||||
'--operation-id <id>',
|
||||
'Operation id stamped onto every emitted event. Generated as a uuid if omitted (phase 1a).',
|
||||
)
|
||||
.action(exec);
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import { registerDocCommand } from './commands/doc';
|
||||
import { registerEvalCommand } from './commands/eval';
|
||||
import { registerFileCommand } from './commands/file';
|
||||
import { registerGenerateCommand } from './commands/generate';
|
||||
import { registerHeteroCommand } from './commands/hetero';
|
||||
import { registerKbCommand } from './commands/kb';
|
||||
import { registerLoginCommand } from './commands/login';
|
||||
import { registerLogoutCommand } from './commands/logout';
|
||||
@@ -62,6 +63,7 @@ export function createProgram() {
|
||||
registerCronCommand(program);
|
||||
registerGenerateCommand(program);
|
||||
registerFileCommand(program);
|
||||
registerHeteroCommand(program);
|
||||
registerSkillCommand(program);
|
||||
registerSessionGroupCommand(program);
|
||||
registerTaskCommand(program);
|
||||
|
||||
@@ -27,22 +27,22 @@ describe('executeToolCall', () => {
|
||||
fs.rmSync(tmpDir, { force: true, recursive: true });
|
||||
});
|
||||
|
||||
it('should dispatch readLocalFile', async () => {
|
||||
it('should dispatch readFile', async () => {
|
||||
const filePath = path.join(tmpDir, 'test.txt');
|
||||
await writeFile(filePath, 'hello world');
|
||||
|
||||
const result = await executeToolCall('readLocalFile', JSON.stringify({ path: filePath }));
|
||||
const result = await executeToolCall('readFile', JSON.stringify({ path: filePath }));
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
const parsed = JSON.parse(result.content);
|
||||
expect(parsed.content).toContain('hello world');
|
||||
});
|
||||
|
||||
it('should dispatch writeLocalFile', async () => {
|
||||
it('should dispatch writeFile', async () => {
|
||||
const filePath = path.join(tmpDir, 'new.txt');
|
||||
|
||||
const result = await executeToolCall(
|
||||
'writeLocalFile',
|
||||
'writeFile',
|
||||
JSON.stringify({ content: 'written', path: filePath }),
|
||||
);
|
||||
|
||||
@@ -50,6 +50,17 @@ describe('executeToolCall', () => {
|
||||
expect(fs.readFileSync(filePath, 'utf8')).toBe('written');
|
||||
});
|
||||
|
||||
it('should dispatch legacy alias readLocalFile', async () => {
|
||||
const filePath = path.join(tmpDir, 'legacy.txt');
|
||||
await writeFile(filePath, 'legacy hello');
|
||||
|
||||
const result = await executeToolCall('readLocalFile', JSON.stringify({ path: filePath }));
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
const parsed = JSON.parse(result.content);
|
||||
expect(parsed.content).toContain('legacy hello');
|
||||
});
|
||||
|
||||
it('should dispatch runCommand', async () => {
|
||||
const result = await executeToolCall(
|
||||
'runCommand',
|
||||
@@ -61,21 +72,21 @@ describe('executeToolCall', () => {
|
||||
expect(parsed.stdout).toContain('dispatched');
|
||||
});
|
||||
|
||||
it('should dispatch listLocalFiles', async () => {
|
||||
it('should dispatch listFiles', async () => {
|
||||
await writeFile(path.join(tmpDir, 'a.txt'), 'a');
|
||||
|
||||
const result = await executeToolCall('listLocalFiles', JSON.stringify({ path: tmpDir }));
|
||||
const result = await executeToolCall('listFiles', JSON.stringify({ path: tmpDir }));
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
const parsed = JSON.parse(result.content);
|
||||
expect(parsed.totalCount).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should dispatch globLocalFiles', async () => {
|
||||
it('should dispatch globFiles', async () => {
|
||||
await writeFile(path.join(tmpDir, 'test.ts'), 'code');
|
||||
|
||||
const result = await executeToolCall(
|
||||
'globLocalFiles',
|
||||
'globFiles',
|
||||
JSON.stringify({ cwd: tmpDir, pattern: '*.ts' }),
|
||||
);
|
||||
|
||||
@@ -84,12 +95,12 @@ describe('executeToolCall', () => {
|
||||
expect(parsed.files).toContain('test.ts');
|
||||
});
|
||||
|
||||
it('should dispatch editLocalFile', async () => {
|
||||
it('should dispatch editFile', async () => {
|
||||
const filePath = path.join(tmpDir, 'edit.txt');
|
||||
await writeFile(filePath, 'old content');
|
||||
|
||||
const result = await executeToolCall(
|
||||
'editLocalFile',
|
||||
'editFile',
|
||||
JSON.stringify({
|
||||
file_path: filePath,
|
||||
new_string: 'new content',
|
||||
@@ -116,7 +127,7 @@ describe('executeToolCall', () => {
|
||||
const filePath = path.join(tmpDir, 'str.txt');
|
||||
await writeFile(filePath, 'content');
|
||||
|
||||
const result = await executeToolCall('readLocalFile', JSON.stringify({ path: filePath }));
|
||||
const result = await executeToolCall('readFile', JSON.stringify({ path: filePath }));
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
// Result should be valid JSON
|
||||
@@ -124,7 +135,7 @@ describe('executeToolCall', () => {
|
||||
});
|
||||
|
||||
it('should return error for invalid JSON arguments', async () => {
|
||||
const result = await executeToolCall('readLocalFile', 'not-json');
|
||||
const result = await executeToolCall('readFile', 'not-json');
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toBeDefined();
|
||||
@@ -141,11 +152,11 @@ describe('executeToolCall', () => {
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('should dispatch searchLocalFiles', async () => {
|
||||
it('should dispatch searchFiles', async () => {
|
||||
await writeFile(path.join(tmpDir, 'search_target.txt'), 'found');
|
||||
|
||||
const result = await executeToolCall(
|
||||
'searchLocalFiles',
|
||||
'searchFiles',
|
||||
JSON.stringify({ directory: tmpDir, keywords: 'search_target' }),
|
||||
);
|
||||
|
||||
|
||||
@@ -11,14 +11,22 @@ import {
|
||||
import { getCommandOutput, killCommand, runCommand } from './shell';
|
||||
|
||||
const methodMap: Record<string, (args: any) => Promise<unknown>> = {
|
||||
editLocalFile,
|
||||
editFile: editLocalFile,
|
||||
getCommandOutput,
|
||||
globLocalFiles,
|
||||
globFiles: globLocalFiles,
|
||||
grepContent,
|
||||
killCommand,
|
||||
listFiles: listLocalFiles,
|
||||
readFile: readLocalFile,
|
||||
runCommand,
|
||||
searchFiles: searchLocalFiles,
|
||||
writeFile: writeLocalFile,
|
||||
|
||||
// Legacy aliases — older Gateway versions may still send the long form
|
||||
editLocalFile,
|
||||
globLocalFiles,
|
||||
listLocalFiles,
|
||||
readLocalFile,
|
||||
runCommand,
|
||||
searchLocalFiles,
|
||||
writeLocalFile,
|
||||
};
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"@lobechat/electron-client-ipc": "workspace:*",
|
||||
"@lobechat/electron-server-ipc": "workspace:*",
|
||||
"@lobechat/file-loaders": "workspace:*",
|
||||
"@lobechat/heterogeneous-agents": "workspace:*",
|
||||
"@lobechat/local-file-shell": "workspace:*",
|
||||
"@lobehub/i18n-cli": "^1.25.1",
|
||||
"@modelcontextprotocol/sdk": "^1.24.3",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
packages:
|
||||
- '../cli'
|
||||
- '../../packages/agent-gateway-client'
|
||||
- '../../packages/heterogeneous-agents'
|
||||
- '../../packages/const'
|
||||
- '../../packages/electron-server-ipc'
|
||||
- '../../packages/electron-client-ipc'
|
||||
|
||||
@@ -26,6 +26,7 @@ export const defaultProxySettings: NetworkProxySettings = {
|
||||
* Storage default values
|
||||
*/
|
||||
export const STORE_DEFAULTS: ElectronMainStore = {
|
||||
appTrayVisible: true,
|
||||
dataSyncConfig: { storageMode: 'cloud' },
|
||||
encryptedTokens: {},
|
||||
gatewayDeviceDescription: '',
|
||||
|
||||
@@ -111,20 +111,39 @@ export default class GatewayConnectionCtr extends ControllerModule {
|
||||
// ─── Tool Call Routing ───
|
||||
|
||||
private async executeToolCall(apiName: string, args: any): Promise<unknown> {
|
||||
const editFile = () => this.localFileCtr.handleEditFile(args);
|
||||
const globFiles = () => this.localFileCtr.handleGlobFiles(args);
|
||||
const listFiles = () => this.localFileCtr.listLocalFiles(args);
|
||||
const moveFiles = () => this.localFileCtr.handleMoveFiles(args);
|
||||
const readFile = () => this.localFileCtr.readFile(args);
|
||||
const searchFiles = () => this.localFileCtr.handleLocalFilesSearch(args);
|
||||
const writeFile = () => this.localFileCtr.handleWriteFile(args);
|
||||
|
||||
const methodMap: Record<string, () => Promise<unknown>> = {
|
||||
editLocalFile: () => this.localFileCtr.handleEditFile(args),
|
||||
globLocalFiles: () => this.localFileCtr.handleGlobFiles(args),
|
||||
editFile,
|
||||
globFiles,
|
||||
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),
|
||||
listFiles,
|
||||
moveFiles,
|
||||
readFile,
|
||||
searchFiles,
|
||||
writeFile,
|
||||
|
||||
getCommandOutput: () => this.shellCommandCtr.handleGetCommandOutput(args),
|
||||
killCommand: () => this.shellCommandCtr.handleKillCommand(args),
|
||||
runCommand: () => this.shellCommandCtr.handleRunCommand(args),
|
||||
|
||||
// Legacy aliases — keep these so older Gateway versions sending the long
|
||||
// names continue to route correctly. `renameLocalFile` is also kept even
|
||||
// though the new surface drops rename (it's now handled by `moveFiles`).
|
||||
editLocalFile: editFile,
|
||||
globLocalFiles: globFiles,
|
||||
listLocalFiles: listFiles,
|
||||
moveLocalFiles: moveFiles,
|
||||
readLocalFile: readFile,
|
||||
renameLocalFile: () => this.localFileCtr.handleRenameFile(args),
|
||||
searchLocalFiles: searchFiles,
|
||||
writeLocalFile: writeFile,
|
||||
};
|
||||
|
||||
const handler = methodMap[apiName];
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { execFile } from 'node:child_process';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { execFile, spawn } from 'node:child_process';
|
||||
import { readFile, stat } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import type {
|
||||
GetGitBranchDiffPayload,
|
||||
GitAheadBehind,
|
||||
GitBranchDiffPatches,
|
||||
GitBranchInfo,
|
||||
GitBranchListItem,
|
||||
GitCheckoutResult,
|
||||
@@ -12,6 +14,7 @@ import type {
|
||||
GitLinkedPullRequestResult,
|
||||
GitPullResult,
|
||||
GitPushResult,
|
||||
GitRemoteBranchListItem,
|
||||
GitWorkingTreeFiles,
|
||||
GitWorkingTreePatch,
|
||||
GitWorkingTreePatches,
|
||||
@@ -25,6 +28,412 @@ import { ControllerModule, IpcMethod } from './index';
|
||||
|
||||
const logger = createLogger('controllers:GitCtr');
|
||||
|
||||
interface DirtyEntry {
|
||||
filePath: string;
|
||||
status: GitFileDiffStatus;
|
||||
}
|
||||
|
||||
interface DiffBlock {
|
||||
isBinary: boolean;
|
||||
patch: string;
|
||||
/** Destination path (or source path for deleted files). */
|
||||
path: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the output of `git diff HEAD --` into one block per file. Each block
|
||||
* starts at a `^diff --git ` line and runs to just before the next one (or
|
||||
* EOF). Path comes from the `+++ b/<path>` line, falling back to `--- a/<path>`
|
||||
* when the destination is `/dev/null` (deletion). Quoted paths (spaces /
|
||||
* non-ASCII when `core.quotepath` is on) are minimally de-escaped.
|
||||
*/
|
||||
const splitBulkDiff = (diffText: string): DiffBlock[] => {
|
||||
if (!diffText) return [];
|
||||
const blocks: DiffBlock[] = [];
|
||||
const headerRe = /^diff --git /gm;
|
||||
const starts: number[] = [];
|
||||
let m: RegExpExecArray | null;
|
||||
while ((m = headerRe.exec(diffText)) !== null) starts.push(m.index);
|
||||
for (let i = 0; i < starts.length; i++) {
|
||||
const start = starts[i];
|
||||
const end = i + 1 < starts.length ? starts[i + 1] : diffText.length;
|
||||
const block = diffText.slice(start, end);
|
||||
const filePath = extractPathFromDiffBlock(block);
|
||||
if (!filePath) continue;
|
||||
blocks.push({
|
||||
isBinary: /^Binary files .* differ$/m.test(block),
|
||||
path: filePath,
|
||||
patch: block,
|
||||
});
|
||||
}
|
||||
return blocks;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pull the file path out of a per-file diff block. Looks at the `+++ b/<path>`
|
||||
* line first (covers add/modify); falls back to `--- a/<path>` for deletes
|
||||
* where `+++` is `/dev/null`; final fallback is the `diff --git a/x b/y`
|
||||
* header line.
|
||||
*/
|
||||
const extractPathFromDiffBlock = (block: string): string | null => {
|
||||
let plusPath: string | null = null;
|
||||
let minusPath: string | null = null;
|
||||
for (const line of block.split('\n')) {
|
||||
if (line.startsWith('+++ ')) {
|
||||
plusPath = parseDiffPathLine(line.slice(4), 'b/');
|
||||
} else if (line.startsWith('--- ')) {
|
||||
minusPath = parseDiffPathLine(line.slice(4), 'a/');
|
||||
}
|
||||
// The file headers always come before the first hunk / binary marker;
|
||||
// bail once we hit either to avoid scanning huge diff bodies.
|
||||
if (line.startsWith('@@') || line.startsWith('Binary files ')) break;
|
||||
}
|
||||
if (plusPath) return plusPath;
|
||||
if (minusPath) return minusPath;
|
||||
// Last-resort: parse the `diff --git a/x b/y` header itself.
|
||||
const header = block.split('\n', 1)[0];
|
||||
const match = /^diff --git a\/.+? b\/(.+)$/.exec(header);
|
||||
return match ? match[1] : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Strip the `a/` or `b/` prefix off a `+++` / `---` line, drop the optional
|
||||
* trailing tab+timestamp, and de-quote git's C-style escaping. Returns null
|
||||
* for `/dev/null` (which means the other side of the diff is the real path).
|
||||
*/
|
||||
const parseDiffPathLine = (raw: string, prefix: 'a/' | 'b/'): string | null => {
|
||||
const tabIdx = raw.indexOf('\t');
|
||||
let p = tabIdx >= 0 ? raw.slice(0, tabIdx) : raw;
|
||||
if (p === '/dev/null') return null;
|
||||
// Quoted form: "b/path with spaces"
|
||||
if (p.startsWith('"') && p.endsWith('"')) {
|
||||
p = dequoteGitPath(p.slice(1, -1));
|
||||
}
|
||||
return p.startsWith(prefix) ? p.slice(prefix.length) : p;
|
||||
};
|
||||
|
||||
export const dequoteGitPath = (s: string): string =>
|
||||
s.replaceAll(/\\(["\\trn]|[0-7]{3})/g, (_, esc: string) => {
|
||||
if (esc === '"') return '"';
|
||||
if (esc === '\\') return '\\';
|
||||
if (esc === 't') return '\t';
|
||||
if (esc === 'r') return '\r';
|
||||
if (esc === 'n') return '\n';
|
||||
return String.fromCodePoint(Number.parseInt(esc, 8));
|
||||
});
|
||||
|
||||
/**
|
||||
* Inverse of {@link dequoteGitPath} — returns either `<prefix><path>` (when
|
||||
* no escaping is needed) or git's C-style quoted form `"<prefix><escaped>"`
|
||||
* (when the path contains TAB / LF / CR / quote / backslash / control bytes).
|
||||
* The prefix lives *inside* the quotes so the output matches what real `git
|
||||
* diff` would emit, e.g. `"a/file\twith tab.txt"` rather than `a/"file\twith
|
||||
* tab.txt"`. Plain spaces are not quoted (git tolerates them; the trailing
|
||||
* ` b/<path>` marker on the diff header is enough to delimit the source).
|
||||
*/
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const NEEDS_QUOTING = /["\\\x00-\x1F\x7F]/;
|
||||
export const quoteGitPath = (prefix: 'a/' | 'b/', filePath: string): string => {
|
||||
const combined = prefix + filePath;
|
||||
if (!NEEDS_QUOTING.test(combined)) return combined;
|
||||
let out = '"';
|
||||
for (const ch of combined) {
|
||||
if (ch === '\\') out += '\\\\';
|
||||
else if (ch === '"') out += '\\"';
|
||||
else if (ch === '\t') out += '\\t';
|
||||
else if (ch === '\n') out += '\\n';
|
||||
else if (ch === '\r') out += '\\r';
|
||||
else {
|
||||
const code = ch.codePointAt(0)!;
|
||||
if (code < 0x20 || code === 0x7f) {
|
||||
out += '\\' + code.toString(8).padStart(3, '0');
|
||||
} else {
|
||||
out += ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out + '"';
|
||||
};
|
||||
|
||||
/**
|
||||
* Status from a single diff block's preamble: `new file mode` → added,
|
||||
* `deleted file mode` → deleted, otherwise modified. Used by branch-diff mode
|
||||
* where there's no `git status` to consult — the diff itself is the source.
|
||||
*/
|
||||
const detectDiffBlockStatus = (block: string): GitFileDiffStatus => {
|
||||
// Only scan up to the first hunk / binary marker so huge bodies aren't walked.
|
||||
for (const line of block.split('\n')) {
|
||||
if (line.startsWith('new file mode ')) return 'added';
|
||||
if (line.startsWith('deleted file mode ')) return 'deleted';
|
||||
if (line.startsWith('@@') || line.startsWith('Binary files ')) break;
|
||||
}
|
||||
return 'modified';
|
||||
};
|
||||
|
||||
/** Walk a patch counting `+`/`-` lines while skipping `+++`/`---` headers. */
|
||||
const countAddDel = (patch: string): { additions: number; deletions: number } => {
|
||||
let additions = 0;
|
||||
let deletions = 0;
|
||||
for (const line of patch.split('\n')) {
|
||||
if (line.startsWith('+++') || line.startsWith('---')) continue;
|
||||
if (line.startsWith('+')) additions++;
|
||||
else if (line.startsWith('-')) deletions++;
|
||||
}
|
||||
return { additions, deletions };
|
||||
};
|
||||
|
||||
const emptyPatch = (entry: DirtyEntry): GitWorkingTreePatch => ({
|
||||
additions: 0,
|
||||
deletions: 0,
|
||||
filePath: entry.filePath,
|
||||
isBinary: false,
|
||||
patch: '',
|
||||
status: entry.status,
|
||||
truncated: false,
|
||||
});
|
||||
|
||||
const buildTrackedPatch = (
|
||||
entry: DirtyEntry,
|
||||
block: DiffBlock,
|
||||
maxBytes: number,
|
||||
): GitWorkingTreePatch => {
|
||||
if (block.isBinary) {
|
||||
return { ...emptyPatch(entry), isBinary: true };
|
||||
}
|
||||
if (block.patch.length > maxBytes) {
|
||||
return { ...emptyPatch(entry), truncated: true };
|
||||
}
|
||||
const { additions, deletions } = countAddDel(block.patch);
|
||||
return {
|
||||
additions,
|
||||
deletions,
|
||||
filePath: entry.filePath,
|
||||
isBinary: false,
|
||||
patch: block.patch,
|
||||
status: entry.status,
|
||||
truncated: false,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Build a synthetic add-only patch for an untracked file by reading it from
|
||||
* disk — replaces the per-file `git diff --no-index /dev/null <file>` fork.
|
||||
* Binary detection uses a NUL-byte sniff over the first 8 KB (matches what
|
||||
* git itself does internally).
|
||||
*/
|
||||
const readUntrackedAsPatch = async (
|
||||
cwd: string,
|
||||
entry: DirtyEntry,
|
||||
maxBytes: number,
|
||||
): Promise<GitWorkingTreePatch> => {
|
||||
const absolute = path.resolve(cwd, entry.filePath);
|
||||
let size: number;
|
||||
try {
|
||||
const s = await stat(absolute);
|
||||
if (!s.isFile()) return emptyPatch(entry);
|
||||
size = s.size;
|
||||
} catch (error: any) {
|
||||
logger.debug('[readUntrackedAsPatch] stat failed', {
|
||||
filePath: entry.filePath,
|
||||
message: error?.message,
|
||||
});
|
||||
return emptyPatch(entry);
|
||||
}
|
||||
// Pre-quote so the path is C-style escaped wherever it lands in the synthetic
|
||||
// patch — raw `entry.filePath` interpolation would emit malformed `diff --git`
|
||||
// / `+++` lines for filenames containing TAB / LF / quote / backslash.
|
||||
const aPath = quoteGitPath('a/', entry.filePath);
|
||||
const bPath = quoteGitPath('b/', entry.filePath);
|
||||
if (size === 0) {
|
||||
return {
|
||||
...emptyPatch(entry),
|
||||
patch:
|
||||
[
|
||||
`diff --git ${aPath} ${bPath}`,
|
||||
'new file mode 100644',
|
||||
'--- /dev/null',
|
||||
`+++ ${bPath}`,
|
||||
].join('\n') + '\n',
|
||||
};
|
||||
}
|
||||
// Cap the synthesized patch by *file* size, not patch size — a 200 KB file
|
||||
// produces a ~200 KB patch (one `+` per line). Close enough.
|
||||
if (size > maxBytes) {
|
||||
return { ...emptyPatch(entry), truncated: true };
|
||||
}
|
||||
let buf: Buffer;
|
||||
try {
|
||||
buf = await readFile(absolute);
|
||||
} catch (error: any) {
|
||||
logger.debug('[readUntrackedAsPatch] read failed', {
|
||||
filePath: entry.filePath,
|
||||
message: error?.message,
|
||||
});
|
||||
return emptyPatch(entry);
|
||||
}
|
||||
const sniffEnd = Math.min(buf.length, 8192);
|
||||
for (let i = 0; i < sniffEnd; i++) {
|
||||
if (buf[i] === 0) return { ...emptyPatch(entry), isBinary: true };
|
||||
}
|
||||
const text = buf.toString('utf8');
|
||||
// text.split('\n') leaves a trailing '' when the file ends with '\n';
|
||||
// exclude it so the hunk header line count matches git's own output.
|
||||
const rawLines = text.split('\n');
|
||||
const trailingEmpty = rawLines.length > 0 && rawLines.at(-1) === '';
|
||||
const lineCount = trailingEmpty ? rawLines.length - 1 : rawLines.length;
|
||||
if (lineCount === 0) {
|
||||
return { ...emptyPatch(entry), patch: '' };
|
||||
}
|
||||
const body = rawLines
|
||||
.slice(0, lineCount)
|
||||
.map((line) => '+' + line)
|
||||
.join('\n');
|
||||
// Mirror `git diff --no-index`'s "no newline at end of file" footer when the
|
||||
// source had no trailing newline — keeps PatchDiff's hunk parser happy.
|
||||
const noNewlineFooter = trailingEmpty ? '' : '\n\\ No newline at end of file';
|
||||
const patch =
|
||||
[
|
||||
`diff --git ${aPath} ${bPath}`,
|
||||
'new file mode 100644',
|
||||
'--- /dev/null',
|
||||
`+++ ${bPath}`,
|
||||
`@@ -0,0 +1,${lineCount} @@`,
|
||||
body,
|
||||
].join('\n') +
|
||||
noNewlineFooter +
|
||||
'\n';
|
||||
return {
|
||||
additions: lineCount,
|
||||
deletions: 0,
|
||||
filePath: entry.filePath,
|
||||
isBinary: false,
|
||||
patch,
|
||||
status: entry.status,
|
||||
truncated: false,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Stream a git invocation's stdout via `spawn` instead of `execFile`'s
|
||||
* fixed-size buffer. Replaces the bulk-diff caller's old 64 MB `maxBuffer`
|
||||
* cap — pipe-buffer-sized chunks accumulate in memory until the process
|
||||
* exits, with no hard ceiling. SIGTERM on timeout. Resolves with the full
|
||||
* stdout string; rejects with an Error carrying `stderr` and `partialStdout`
|
||||
* fields so callers can salvage partial output (or fall back) on failure.
|
||||
*/
|
||||
const runGitCaptureStream = (cwd: string, args: string[], timeoutMs: number): Promise<string> =>
|
||||
new Promise((resolve, reject) => {
|
||||
const child = spawn('git', args, { cwd });
|
||||
const stdoutChunks: Buffer[] = [];
|
||||
let stderrBuf = '';
|
||||
let timedOut = false;
|
||||
const timer = setTimeout(() => {
|
||||
timedOut = true;
|
||||
child.kill('SIGTERM');
|
||||
}, timeoutMs);
|
||||
child.stdout.on('data', (chunk: Buffer) => stdoutChunks.push(chunk));
|
||||
child.stderr.on('data', (chunk: Buffer) => {
|
||||
stderrBuf += chunk.toString('utf8');
|
||||
});
|
||||
child.on('error', (err) => {
|
||||
clearTimeout(timer);
|
||||
reject(Object.assign(err, { stderr: stderrBuf }));
|
||||
});
|
||||
child.on('close', (code) => {
|
||||
clearTimeout(timer);
|
||||
const stdout = Buffer.concat(stdoutChunks).toString('utf8');
|
||||
if (timedOut) {
|
||||
const err: any = new Error('git command timed out');
|
||||
err.stderr = stderrBuf;
|
||||
err.partialStdout = stdout;
|
||||
return reject(err);
|
||||
}
|
||||
// `git diff HEAD` (without --exit-code) exits 0 even when there are
|
||||
// diffs; non-zero is therefore a real error.
|
||||
if (code !== 0) {
|
||||
const err: any = new Error(`git exited with code ${code}`);
|
||||
err.code = code;
|
||||
err.stderr = stderrBuf;
|
||||
err.partialStdout = stdout;
|
||||
return reject(err);
|
||||
}
|
||||
resolve(stdout);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Last-resort per-file diff for tracked entries the bulk diff didn't cover —
|
||||
* either because the bulk command failed entirely or because git emitted no
|
||||
* patch for a path the status step listed (rare race with concurrent writes).
|
||||
* Mirrors the original per-file behavior so individual files keep their
|
||||
* patches even when the bulk fast-path is unavailable.
|
||||
*/
|
||||
const fetchTrackedPatchPerFile = async (
|
||||
cwd: string,
|
||||
entry: DirtyEntry,
|
||||
maxBytes: number,
|
||||
): Promise<GitWorkingTreePatch> => {
|
||||
const execFileAsync = promisify(execFile);
|
||||
let text: string;
|
||||
try {
|
||||
const { stdout } = await execFileAsync(
|
||||
'git',
|
||||
['-c', 'core.quotepath=off', 'diff', '--no-color', 'HEAD', '--', entry.filePath],
|
||||
{
|
||||
cwd,
|
||||
encoding: 'utf8',
|
||||
maxBuffer: maxBytes * 4,
|
||||
timeout: 10_000,
|
||||
},
|
||||
);
|
||||
text = stdout as string;
|
||||
} catch (error: any) {
|
||||
logger.debug('[fetchTrackedPatchPerFile] diff failed', {
|
||||
filePath: entry.filePath,
|
||||
stderr: error?.stderr?.toString?.() ?? error?.stderr,
|
||||
});
|
||||
return emptyPatch(entry);
|
||||
}
|
||||
if (text.length > maxBytes) return { ...emptyPatch(entry), truncated: true };
|
||||
if (/^Binary files .* differ$/m.test(text)) return { ...emptyPatch(entry), isBinary: true };
|
||||
if (!text) return emptyPatch(entry);
|
||||
const { additions, deletions } = countAddDel(text);
|
||||
return {
|
||||
additions,
|
||||
deletions,
|
||||
filePath: entry.filePath,
|
||||
isBinary: false,
|
||||
patch: text,
|
||||
status: entry.status,
|
||||
truncated: false,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Bounded `Promise.all` — runs at most `limit` async tasks at a time. Used
|
||||
* for the per-file fallback so we cap fork pressure at a small constant
|
||||
* instead of replaying the original 200-parallel `git diff` storm.
|
||||
*/
|
||||
const mapWithConcurrency = async <T, R>(
|
||||
items: T[],
|
||||
limit: number,
|
||||
fn: (item: T) => Promise<R>,
|
||||
): Promise<R[]> => {
|
||||
const results: R[] = Array.from({ length: items.length });
|
||||
let cursor = 0;
|
||||
const workerCount = Math.min(limit, items.length);
|
||||
await Promise.all(
|
||||
Array.from({ length: workerCount }, async () => {
|
||||
while (true) {
|
||||
const idx = cursor++;
|
||||
if (idx >= items.length) return;
|
||||
results[idx] = await fn(items[idx]);
|
||||
}
|
||||
}),
|
||||
);
|
||||
return results;
|
||||
};
|
||||
|
||||
export default class GitController extends ControllerModule {
|
||||
static override readonly groupName = 'git';
|
||||
|
||||
@@ -165,6 +574,54 @@ export default class GitController extends ControllerModule {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List remote branches under `refs/remotes/origin/*`, ordered by most
|
||||
* recent commit. The `HEAD` symref is filtered out and the resolved
|
||||
* default branch is flagged via `isDefault` so the UI can render it
|
||||
* with a marker. Used by the Review panel's branch-compare picker.
|
||||
*/
|
||||
@IpcMethod()
|
||||
async listGitRemoteBranches(dirPath: string): Promise<GitRemoteBranchListItem[]> {
|
||||
const execFileAsync = promisify(execFile);
|
||||
let defaultRef: string | undefined;
|
||||
try {
|
||||
const { stdout } = await execFileAsync(
|
||||
'git',
|
||||
['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'],
|
||||
{ cwd: dirPath, timeout: 5000 },
|
||||
);
|
||||
defaultRef = stdout.trim() || undefined;
|
||||
} catch {
|
||||
defaultRef = undefined;
|
||||
}
|
||||
try {
|
||||
const { stdout } = await execFileAsync(
|
||||
'git',
|
||||
[
|
||||
'for-each-ref',
|
||||
'--sort=-committerdate',
|
||||
'--format=%(refname:short)',
|
||||
'refs/remotes/origin',
|
||||
],
|
||||
{ cwd: dirPath, timeout: 5000 },
|
||||
);
|
||||
return stdout
|
||||
.replaceAll('\r', '')
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.filter((name) => name.length > 0 && name !== 'origin/HEAD' && !name.endsWith('/HEAD'))
|
||||
.map((name) => ({ isDefault: name === defaultRef, name }));
|
||||
} catch (error: any) {
|
||||
logger.warn('[listGitRemoteBranches] git command failed', {
|
||||
code: error?.code,
|
||||
cwd: dirPath,
|
||||
message: error?.message,
|
||||
stderr: error?.stderr?.toString?.() ?? error?.stderr,
|
||||
});
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bucket dirty files into added / modified / deleted via `git status --porcelain -z`.
|
||||
* Each file is counted once: untracked (`??`) and staged-add (`A`) → added,
|
||||
@@ -266,14 +723,18 @@ export default class GitController extends ControllerModule {
|
||||
|
||||
/**
|
||||
* Pull every dirty file's unified diff in one shot — one IPC call returns
|
||||
* the patches the renderer needs to render `<PatchDiff />` per file. We do
|
||||
* the per-file `git diff` invocations in parallel inside this method so
|
||||
* the renderer doesn't have to fan out N IPC round trips.
|
||||
* the patches the renderer needs to render `<PatchDiff />` per file.
|
||||
*
|
||||
* Tracked changes (modified / deleted / staged-A) come from
|
||||
* `git diff HEAD -- <file>`; pure untracked files come from
|
||||
* `git diff --no-index /dev/null <file>` (which exits with code 1 when
|
||||
* there are differences — that's success, not failure).
|
||||
* Tracked changes (modified / deleted / staged-A) all come from a *single*
|
||||
* `git diff HEAD --` invocation that we split per-file in JS — fork-bombing
|
||||
* the main process with N parallel `git diff` subprocesses was costing us
|
||||
* ~5–10ms × N in fork overhead plus `.git/index` lock contention, and the
|
||||
* libuv worker pool stayed busy while other IPC handlers queued. One
|
||||
* subprocess instead of N keeps the freeze invisible.
|
||||
*
|
||||
* Untracked files are read directly with `fs.readFile` and a synthetic
|
||||
* `--- /dev/null / +++ b/<path>` patch is built in Node — no `git diff`
|
||||
* subprocess at all.
|
||||
*
|
||||
* Per-file patches are capped at 256 KB; oversized or binary entries get an
|
||||
* empty `patch` string and a flag the renderer can use for a placeholder.
|
||||
@@ -291,7 +752,7 @@ export default class GitController extends ControllerModule {
|
||||
|
||||
// Step 1 — classify every dirty path. Mirrors getGitWorkingTreeFiles but
|
||||
// also distinguishes untracked (`??`) from staged-add (`A`) so we can pick
|
||||
// the right diff command per entry.
|
||||
// the right path (git diff vs raw read) per entry.
|
||||
const entries: Entry[] = [];
|
||||
try {
|
||||
const { stdout } = await execFileAsync('git', ['status', '--porcelain', '-z'], {
|
||||
@@ -330,100 +791,163 @@ export default class GitController extends ControllerModule {
|
||||
return { patches: [] };
|
||||
}
|
||||
|
||||
// Walk the patch line-by-line counting `+`/`-` payload lines while
|
||||
// skipping the `+++ b/...` / `--- a/...` headers (they look like
|
||||
// additions/deletions but aren't). Cheap enough to do inline per file —
|
||||
// each patch is capped at MAX_PATCH_BYTES.
|
||||
const countAddDel = (patch: string): { additions: number; deletions: number } => {
|
||||
let additions = 0;
|
||||
let deletions = 0;
|
||||
for (const line of patch.split('\n')) {
|
||||
if (line.startsWith('+++') || line.startsWith('---')) continue;
|
||||
if (line.startsWith('+')) additions++;
|
||||
else if (line.startsWith('-')) deletions++;
|
||||
// Step 2a — single bulk `git diff HEAD` for every tracked dirty path,
|
||||
// then split per-file in JS. We pass paths explicitly (not all) so a
|
||||
// huge unrelated working tree doesn't pull extra patches into the
|
||||
// stream. Output is streamed via spawn so there's no maxBuffer ceiling
|
||||
// — even a multi-hundred-MB combined diff lands intact, and any partial
|
||||
// output recovered from a failed run still feeds the per-file fallback.
|
||||
const trackedEntries = entries.filter((e) => !e.isUntracked);
|
||||
const trackedByPath = new Map(trackedEntries.map((e) => [e.filePath, e]));
|
||||
const trackedPatches = new Map<string, GitWorkingTreePatch>();
|
||||
if (trackedEntries.length > 0) {
|
||||
let bulkDiff = '';
|
||||
try {
|
||||
bulkDiff = await runGitCaptureStream(
|
||||
dirPath,
|
||||
[
|
||||
'-c',
|
||||
'core.quotepath=off',
|
||||
'diff',
|
||||
'--no-color',
|
||||
'HEAD',
|
||||
'--',
|
||||
...trackedEntries.map((e) => e.filePath),
|
||||
],
|
||||
30_000,
|
||||
);
|
||||
} catch (error: any) {
|
||||
logger.warn('[getGitWorkingTreePatches] bulk diff failed; per-file fallback', {
|
||||
cwd: dirPath,
|
||||
stderr: error?.stderr?.toString?.() ?? error?.stderr,
|
||||
});
|
||||
// Salvage any patches that did stream through before the failure —
|
||||
// the per-file fallback below only retries the stragglers.
|
||||
if (typeof error?.partialStdout === 'string') bulkDiff = error.partialStdout;
|
||||
}
|
||||
return { additions, deletions };
|
||||
};
|
||||
for (const block of splitBulkDiff(bulkDiff)) {
|
||||
const entry = trackedByPath.get(block.path);
|
||||
if (!entry) continue;
|
||||
trackedPatches.set(entry.filePath, buildTrackedPatch(entry, block, MAX_PATCH_BYTES));
|
||||
}
|
||||
// Anything the bulk diff didn't cover (bulk crashed, race-with-write,
|
||||
// or git emitted no patch for a path status flagged dirty) gets a
|
||||
// per-file retry. Concurrency-capped to avoid the original fork storm.
|
||||
const stragglers = trackedEntries.filter((e) => !trackedPatches.has(e.filePath));
|
||||
if (stragglers.length > 0) {
|
||||
const recovered = await mapWithConcurrency(stragglers, 8, (entry) =>
|
||||
fetchTrackedPatchPerFile(dirPath, entry, MAX_PATCH_BYTES),
|
||||
);
|
||||
for (const patch of recovered) trackedPatches.set(patch.filePath, patch);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2 — per-file diff in parallel. `--no-index` exits 1 when there's a
|
||||
// diff (which is the expected outcome for untracked files), so we have to
|
||||
// pull stdout off the rejected error rather than letting it throw.
|
||||
const patches = await Promise.all(
|
||||
entries.map(async ({ filePath, isUntracked, status }): Promise<GitWorkingTreePatch> => {
|
||||
const args = isUntracked
|
||||
? ['diff', '--no-color', '--no-index', '/dev/null', filePath]
|
||||
: ['diff', '--no-color', 'HEAD', '--', filePath];
|
||||
|
||||
let text: string;
|
||||
try {
|
||||
const { stdout } = await execFileAsync('git', args, {
|
||||
cwd: dirPath,
|
||||
encoding: 'utf8',
|
||||
maxBuffer: MAX_PATCH_BYTES * 4,
|
||||
timeout: 10_000,
|
||||
});
|
||||
text = stdout as string;
|
||||
} catch (error: any) {
|
||||
if (error?.stdout == null) {
|
||||
logger.debug('[getGitWorkingTreePatches] diff failed', {
|
||||
filePath,
|
||||
status,
|
||||
stderr: error?.stderr?.toString?.() ?? error?.stderr,
|
||||
});
|
||||
return {
|
||||
additions: 0,
|
||||
deletions: 0,
|
||||
filePath,
|
||||
isBinary: false,
|
||||
patch: '',
|
||||
status,
|
||||
truncated: false,
|
||||
};
|
||||
}
|
||||
text = error.stdout.toString();
|
||||
}
|
||||
|
||||
if (text.length > MAX_PATCH_BYTES) {
|
||||
return {
|
||||
additions: 0,
|
||||
deletions: 0,
|
||||
filePath,
|
||||
isBinary: false,
|
||||
patch: '',
|
||||
status,
|
||||
truncated: true,
|
||||
};
|
||||
}
|
||||
if (/^Binary files .* differ$/m.test(text)) {
|
||||
return {
|
||||
additions: 0,
|
||||
deletions: 0,
|
||||
filePath,
|
||||
isBinary: true,
|
||||
patch: '',
|
||||
status,
|
||||
truncated: false,
|
||||
};
|
||||
}
|
||||
const { additions, deletions } = countAddDel(text);
|
||||
return {
|
||||
additions,
|
||||
deletions,
|
||||
filePath,
|
||||
isBinary: false,
|
||||
patch: text,
|
||||
status,
|
||||
truncated: false,
|
||||
};
|
||||
}),
|
||||
// Step 2b — read untracked files directly in Node. fs.readFile is bounded
|
||||
// by libuv's thread pool (4 by default) so unbounded Promise.all is fine.
|
||||
const untrackedEntries = entries.filter((e) => e.isUntracked);
|
||||
const untrackedPatches = await Promise.all(
|
||||
untrackedEntries.map((entry) => readUntrackedAsPatch(dirPath, entry, MAX_PATCH_BYTES)),
|
||||
);
|
||||
|
||||
// Re-bucket so the UI sees added → modified → deleted (matches the
|
||||
// working-tree popover order).
|
||||
// Step 3 — combine + sort to match the working-tree popover order.
|
||||
const order: Record<GitFileDiffStatus, number> = { added: 0, modified: 1, deleted: 2 };
|
||||
const allPatches: GitWorkingTreePatch[] = [...trackedPatches.values(), ...untrackedPatches];
|
||||
allPatches.sort((a, b) => order[a.status] - order[b.status]);
|
||||
|
||||
return { patches: allPatches };
|
||||
}
|
||||
|
||||
/**
|
||||
* Diff every changed file between the current HEAD and the remote default
|
||||
* branch (resolved via `refs/remotes/origin/HEAD` — typically `origin/main`
|
||||
* or `origin/canary`). Uses `<base>...HEAD` so the result is "what this
|
||||
* branch added since it forked", ignoring upstream-only commits.
|
||||
*
|
||||
* Best-effort `git fetch` first so the comparison reflects the latest
|
||||
* remote state; fetch failures (offline / no creds / no `origin`) are
|
||||
* swallowed and we fall back to whatever cached refs exist. Returns
|
||||
* `baseRef: undefined` + empty patches when no remote default is set —
|
||||
* the renderer surfaces a "noBaseRef" hint in that case.
|
||||
*
|
||||
* Patch parsing reuses the same bulk-split + size-cap path as the working
|
||||
* tree variant; status comes from each diff block's preamble (no `git
|
||||
* status` cross-reference needed since every block is from history).
|
||||
*/
|
||||
@IpcMethod()
|
||||
async getGitBranchDiff(payload: GetGitBranchDiffPayload): Promise<GitBranchDiffPatches> {
|
||||
const { path: dirPath, baseRef: baseRefOverride } = payload;
|
||||
const MAX_PATCH_BYTES = 256 * 1024;
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
// Step 1 — best-effort fetch so origin/<default> reflects remote HEAD.
|
||||
try {
|
||||
await execFileAsync('git', ['fetch', '--no-tags', '--quiet', 'origin'], {
|
||||
cwd: dirPath,
|
||||
timeout: 10_000,
|
||||
});
|
||||
} catch {
|
||||
// swallow — fall through to cached refs
|
||||
}
|
||||
|
||||
// Step 2 — pick the comparison base. When the caller passes an explicit
|
||||
// override (e.g. user picked a non-default branch in the UI) we trust it;
|
||||
// otherwise we resolve `refs/remotes/origin/HEAD`. The default may be
|
||||
// missing on repos cloned with --no-checkout or after a remote rename —
|
||||
// surface a "noBaseRef" empty state in that case so the user can run
|
||||
// `git remote set-head origin --auto` themselves.
|
||||
let baseRef: string | undefined = baseRefOverride;
|
||||
if (!baseRef) {
|
||||
try {
|
||||
const { stdout } = await execFileAsync(
|
||||
'git',
|
||||
['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'],
|
||||
{ cwd: dirPath, timeout: 5000 },
|
||||
);
|
||||
baseRef = stdout.trim() || undefined;
|
||||
} catch {
|
||||
baseRef = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// headRef populated even when baseRef is missing so the UI can still
|
||||
// surface "fix/foo ← ?" instead of going completely blank.
|
||||
const headRef = (await this.getGitBranch(dirPath)).branch;
|
||||
|
||||
if (!baseRef) {
|
||||
return { headRef, patches: [] };
|
||||
}
|
||||
|
||||
// Step 3 — single bulk diff against the merge base. Three-dot semantics
|
||||
// (`base...HEAD`) ignore commits added to base after the branch forked,
|
||||
// matching what users expect from "compare branch" UI on GitHub. Stream
|
||||
// capture mirrors the working-tree path so multi-MB diffs land intact.
|
||||
let bulkDiff = '';
|
||||
try {
|
||||
bulkDiff = await runGitCaptureStream(
|
||||
dirPath,
|
||||
['-c', 'core.quotepath=off', 'diff', '--no-color', `${baseRef}...HEAD`],
|
||||
30_000,
|
||||
);
|
||||
} catch (error: any) {
|
||||
logger.warn('[getGitBranchDiff] diff failed', {
|
||||
baseRef,
|
||||
cwd: dirPath,
|
||||
stderr: error?.stderr?.toString?.() ?? error?.stderr,
|
||||
});
|
||||
if (typeof error?.partialStdout === 'string') bulkDiff = error.partialStdout;
|
||||
}
|
||||
|
||||
// Step 4 — split + classify per-file from the diff preamble alone.
|
||||
const patches: GitWorkingTreePatch[] = [];
|
||||
for (const block of splitBulkDiff(bulkDiff)) {
|
||||
const status = detectDiffBlockStatus(block.patch);
|
||||
patches.push(buildTrackedPatch({ filePath: block.path, status }, block, MAX_PATCH_BYTES));
|
||||
}
|
||||
|
||||
const order: Record<GitFileDiffStatus, number> = { added: 0, modified: 1, deleted: 2 };
|
||||
patches.sort((a, b) => order[a.status] - order[b.status]);
|
||||
|
||||
return { patches };
|
||||
return { baseRef, headRef, patches };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import type { ChildProcess } from 'node:child_process';
|
||||
import { spawn } from 'node:child_process';
|
||||
import { createHash, randomUUID } from 'node:crypto';
|
||||
import { access, appendFile, mkdir, readFile, writeFile } from 'node:fs/promises';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { access, appendFile, mkdir, writeFile } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import type { Readable, Writable } from 'node:stream';
|
||||
import { finished as streamFinished } from 'node:stream/promises';
|
||||
|
||||
import type { HeterogeneousAgentSessionError } from '@lobechat/electron-client-ipc';
|
||||
import {
|
||||
@@ -13,14 +14,17 @@ import {
|
||||
CODEX_CLI_INSTALL_DOCS_URL,
|
||||
HeterogeneousAgentSessionErrorCode,
|
||||
} from '@lobechat/electron-client-ipc';
|
||||
import type { AgentContentBlock } from '@lobechat/heterogeneous-agents/spawn';
|
||||
import {
|
||||
AgentStreamPipeline,
|
||||
buildAgentInput,
|
||||
materializeImageToPath,
|
||||
normalizeImage,
|
||||
} from '@lobechat/heterogeneous-agents/spawn';
|
||||
import { app as electronApp, BrowserWindow } from 'electron';
|
||||
|
||||
import { getHeterogeneousAgentDriver } from '@/modules/heterogeneousAgent';
|
||||
import { CodexFileChangeTracker } from '@/modules/heterogeneousAgent/codexFileChangeTracker';
|
||||
import type {
|
||||
HeterogeneousAgentImageAttachment,
|
||||
HeterogeneousAgentParsedOutput,
|
||||
} from '@/modules/heterogeneousAgent/types';
|
||||
import type { HeterogeneousAgentImageAttachment } from '@/modules/heterogeneousAgent/types';
|
||||
import { buildProxyEnv } from '@/modules/networkProxy/envBuilder';
|
||||
import { detectHeterogeneousCliCommand } from '@/modules/toolDetectors';
|
||||
import { createLogger } from '@/utils/logger';
|
||||
@@ -52,16 +56,6 @@ const CODEX_RESUME_CWD_MISMATCH_PATTERNS = [
|
||||
/** Directory under appStoragePath for caching downloaded files */
|
||||
const FILE_CACHE_DIR = 'heteroAgent/files';
|
||||
const CLI_TRACE_DIR = '.heerogeneous-tracing';
|
||||
const IMAGE_EXTENSIONS_BY_MIME = {
|
||||
'image/gif': '.gif',
|
||||
'image/jpg': '.jpg',
|
||||
'image/jpeg': '.jpg',
|
||||
'image/pjpeg': '.jpg',
|
||||
'image/png': '.png',
|
||||
'image/webp': '.webp',
|
||||
'image/x-png': '.png',
|
||||
} as const satisfies Record<string, string>;
|
||||
const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
||||
const CODEX_STDERR_STATUS_LINE = 'Reading prompt from stdin...';
|
||||
const CODEX_WARN_LOG_PATTERN = /^\d{4}-\d{2}-\d{2}T\S+\s+WARN\s+/;
|
||||
const CODEX_LOG_PATTERN = /^\d{4}-\d{2}-\d{2}T\S+\s+(?:DEBUG|ERROR|INFO|TRACE|WARN)\s+/;
|
||||
@@ -91,6 +85,12 @@ interface StartSessionResult {
|
||||
interface SendPromptParams {
|
||||
/** Image attachments to include in the prompt (downloaded from url, cached by id) */
|
||||
imageList?: HeterogeneousAgentImageAttachment[];
|
||||
/**
|
||||
* Renderer-side operation id stamped onto every emitted `AgentStreamEvent`.
|
||||
* Required: producer-side conversion is the V3 contract — by the time events
|
||||
* reach the renderer they must already carry the operation they belong to.
|
||||
*/
|
||||
operationId: string;
|
||||
prompt: string;
|
||||
sessionId: string;
|
||||
}
|
||||
@@ -148,7 +148,7 @@ interface CliTraceSession {
|
||||
* prompt transport, resume semantics, and raw stream shape without turning
|
||||
* this controller into a giant `switch`.
|
||||
*
|
||||
* Lifecycle: startSession → sendPrompt → (heteroAgentRawLine broadcasts) → stopSession
|
||||
* Lifecycle: startSession → sendPrompt → (heteroAgentEvent broadcasts) → stopSession
|
||||
*/
|
||||
export default class HeterogeneousAgentCtr extends ControllerModule {
|
||||
static override readonly groupName = 'heterogeneousAgent';
|
||||
@@ -574,125 +574,56 @@ export default class HeterogeneousAgentCtr extends ControllerModule {
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a filesystem-safe cache key for attachments.
|
||||
*
|
||||
* Never use the raw image id as a path segment — upstream callers can persist
|
||||
* arbitrary ids and path.join would treat traversal sequences as real
|
||||
* directories. A stable hash preserves cache hits without trusting the id as a
|
||||
* filename.
|
||||
* Convert a desktop image attachment list into shared content blocks. Each
|
||||
* attachment's id is preserved as the cache key so repeated prompts hit the
|
||||
* same on-disk entries.
|
||||
*/
|
||||
private getImageCacheKey(imageId: string): string {
|
||||
return createHash('sha256').update(imageId).digest('hex');
|
||||
private toImageContentBlocks(
|
||||
imageList: HeterogeneousAgentImageAttachment[],
|
||||
): AgentContentBlock[] {
|
||||
return imageList.map((image) => ({
|
||||
source: { id: image.id, type: 'url', url: image.url },
|
||||
type: 'image',
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Download an image by URL, with local disk cache keyed by id.
|
||||
* Build a Claude Code stream-json user message with text + base64 images.
|
||||
* Delegates to the shared `buildAgentInput`; the desktop wrapper exists only
|
||||
* to preserve the helper signature consumed by existing drivers.
|
||||
*/
|
||||
private async resolveImage(
|
||||
image: HeterogeneousAgentImageAttachment,
|
||||
): Promise<{ buffer: Buffer; mimeType: string }> {
|
||||
const cacheDir = this.fileCacheDir;
|
||||
const cacheKey = this.getImageCacheKey(image.id);
|
||||
const metaPath = path.join(cacheDir, `${cacheKey}.meta`);
|
||||
const dataPath = path.join(cacheDir, cacheKey);
|
||||
private async buildStreamJsonInput(
|
||||
prompt: string,
|
||||
imageList: HeterogeneousAgentImageAttachment[] = [],
|
||||
): Promise<string> {
|
||||
const blocks: AgentContentBlock[] = [];
|
||||
if (prompt && prompt.length > 0) blocks.push({ text: prompt, type: 'text' });
|
||||
blocks.push(...this.toImageContentBlocks(imageList));
|
||||
|
||||
// Check cache first
|
||||
try {
|
||||
const metaRaw = await readFile(metaPath, 'utf8');
|
||||
const meta = JSON.parse(metaRaw);
|
||||
const buffer = await readFile(dataPath);
|
||||
logger.debug('Image cache hit:', image.id);
|
||||
return { buffer, mimeType: meta.mimeType || 'image/png' };
|
||||
} catch {
|
||||
// Cache miss — download
|
||||
}
|
||||
|
||||
logger.info('Downloading image:', image.id);
|
||||
|
||||
const res = await fetch(image.url);
|
||||
if (!res.ok)
|
||||
throw new Error(`Failed to download image ${image.id}: ${res.status} ${res.statusText}`);
|
||||
|
||||
const arrayBuffer = await res.arrayBuffer();
|
||||
const buffer = Buffer.from(arrayBuffer);
|
||||
const mimeType = res.headers.get('content-type') || 'image/png';
|
||||
|
||||
// Write to cache
|
||||
await mkdir(cacheDir, { recursive: true });
|
||||
await writeFile(dataPath, buffer);
|
||||
await writeFile(metaPath, JSON.stringify({ id: image.id, mimeType }));
|
||||
logger.debug('Image cached:', image.id, `${buffer.length} bytes`);
|
||||
|
||||
return { buffer, mimeType };
|
||||
}
|
||||
|
||||
private normalizeMimeType(mimeType: string): string {
|
||||
return mimeType.split(';')[0]?.trim().toLowerCase() || '';
|
||||
}
|
||||
|
||||
private guessImageExtensionByBuffer(buffer: Buffer): string | undefined {
|
||||
if (buffer.subarray(0, PNG_SIGNATURE.length).equals(PNG_SIGNATURE)) return '.png';
|
||||
if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) return '.jpg';
|
||||
|
||||
const gifSignature = buffer.subarray(0, 6).toString('ascii');
|
||||
if (gifSignature === 'GIF87a' || gifSignature === 'GIF89a') return '.gif';
|
||||
|
||||
if (
|
||||
buffer.subarray(0, 4).toString('ascii') === 'RIFF' &&
|
||||
buffer.subarray(8, 12).toString('ascii') === 'WEBP'
|
||||
) {
|
||||
return '.webp';
|
||||
}
|
||||
}
|
||||
|
||||
private guessImageExtension(
|
||||
mimeType: string,
|
||||
image: HeterogeneousAgentImageAttachment,
|
||||
buffer: Buffer,
|
||||
): string | undefined {
|
||||
const knownByMime = IMAGE_EXTENSIONS_BY_MIME[this.normalizeMimeType(mimeType)];
|
||||
if (knownByMime) return knownByMime;
|
||||
|
||||
try {
|
||||
const pathname = new URL(image.url).pathname;
|
||||
const ext = path.extname(pathname).toLowerCase();
|
||||
if (ext) return ext === '.jpeg' ? '.jpg' : ext;
|
||||
} catch {
|
||||
// Fall through to byte sniffing below.
|
||||
}
|
||||
|
||||
return this.guessImageExtensionByBuffer(buffer);
|
||||
const plan = await buildAgentInput('claude-code', blocks, { cacheDir: this.fileCacheDir });
|
||||
return plan.stdin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Materialize an image attachment into a stable local file path so CLIs like
|
||||
* Codex can consume it through `--image <file>`.
|
||||
* Materialize image attachments into stable filesystem paths for path-mode
|
||||
* agents (Codex `--image <file>`). Fails the prompt if any image cannot be
|
||||
* fetched / decoded — partially-attached prompts confuse the agent more
|
||||
* than they help.
|
||||
*/
|
||||
private async resolveCliImagePath(image: HeterogeneousAgentImageAttachment): Promise<string> {
|
||||
const { buffer, mimeType } = await this.resolveImage(image);
|
||||
const cacheKey = this.getImageCacheKey(image.id);
|
||||
const ext = this.guessImageExtension(mimeType, image, buffer);
|
||||
if (!ext) {
|
||||
throw new Error(`Unsupported image type for ${image.id}`);
|
||||
}
|
||||
|
||||
const filePath = path.join(this.fileCacheDir, `${cacheKey}${ext}`);
|
||||
|
||||
try {
|
||||
await access(filePath);
|
||||
} catch {
|
||||
await mkdir(this.fileCacheDir, { recursive: true });
|
||||
await writeFile(filePath, buffer);
|
||||
}
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
private async resolveCliImagePaths(
|
||||
imageList: HeterogeneousAgentImageAttachment[] = [],
|
||||
): Promise<string[]> {
|
||||
if (imageList.length === 0) return [];
|
||||
|
||||
const cacheDir = this.fileCacheDir;
|
||||
const results = await Promise.allSettled(
|
||||
imageList.map((image) => this.resolveCliImagePath(image)),
|
||||
imageList.map(async (image) => {
|
||||
const normalized = await normalizeImage(
|
||||
{ id: image.id, type: 'url', url: image.url },
|
||||
{ cacheDir },
|
||||
);
|
||||
return materializeImageToPath(normalized, cacheDir);
|
||||
}),
|
||||
);
|
||||
|
||||
const imagePaths: string[] = [];
|
||||
@@ -718,38 +649,6 @@ export default class HeterogeneousAgentCtr extends ControllerModule {
|
||||
return imagePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a stream-json user message with text + optional image content blocks.
|
||||
*/
|
||||
private async buildStreamJsonInput(
|
||||
prompt: string,
|
||||
imageList: HeterogeneousAgentImageAttachment[] = [],
|
||||
): Promise<string> {
|
||||
const content: any[] = [];
|
||||
if (prompt && prompt.length > 0) content.push({ text: prompt, type: 'text' });
|
||||
|
||||
for (const image of imageList) {
|
||||
try {
|
||||
const { buffer, mimeType } = await this.resolveImage(image);
|
||||
content.push({
|
||||
source: {
|
||||
data: buffer.toString('base64'),
|
||||
media_type: mimeType,
|
||||
type: 'base64',
|
||||
},
|
||||
type: 'image',
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error(`Failed to resolve image ${image.id}:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
return `${JSON.stringify({
|
||||
message: { content, role: 'user' },
|
||||
type: 'user',
|
||||
})}\n`;
|
||||
}
|
||||
|
||||
// ─── IPC methods ───
|
||||
|
||||
/**
|
||||
@@ -780,8 +679,9 @@ export default class HeterogeneousAgentCtr extends ControllerModule {
|
||||
/**
|
||||
* Send a prompt to an agent session.
|
||||
*
|
||||
* Spawns the CLI process with preset flags. Broadcasts each stdout line
|
||||
* as an `heteroAgentRawLine` event — Renderer side parses and adapts.
|
||||
* Spawns the CLI process with preset flags. Pipes each stdout chunk through
|
||||
* the shared `AgentStreamPipeline` (JSONL → adapter → toStreamEvent) and
|
||||
* broadcasts the resulting `AgentStreamEvent`s on `heteroAgentEvent`.
|
||||
*/
|
||||
@IpcMethod()
|
||||
async sendPrompt(params: SendPromptParams): Promise<void> {
|
||||
@@ -853,42 +753,49 @@ export default class HeterogeneousAgentCtr extends ControllerModule {
|
||||
}
|
||||
|
||||
session.process = proc;
|
||||
const streamProcessor = driver.createStreamProcessor();
|
||||
const codexFileChangeTracker =
|
||||
session.agentType === 'codex' ? new CodexFileChangeTracker() : undefined;
|
||||
|
||||
// Producer-side conversion (V3 contract): JSONL framing + adapter +
|
||||
// toStreamEvent all run inside the shared pipeline, so renderer + future
|
||||
// server `heteroIngest` see the same `AgentStreamEvent` wire shape with
|
||||
// no per-consumer adapter. The pipeline auto-wires the Codex
|
||||
// file-change line-stat tracker when `agentType === 'codex'`, so this
|
||||
// controller stays agent-agnostic.
|
||||
const pipeline = new AgentStreamPipeline({
|
||||
agentType: session.agentType,
|
||||
operationId: params.operationId,
|
||||
});
|
||||
let stdoutBroadcastQueue: Promise<void> = Promise.resolve();
|
||||
|
||||
const broadcastParsedOutputs = (parsedOutputs: HeterogeneousAgentParsedOutput[]) => {
|
||||
const broadcastPipelineBatch = (produce: () => ReturnType<AgentStreamPipeline['push']>) => {
|
||||
stdoutBroadcastQueue = stdoutBroadcastQueue
|
||||
.then(async () => {
|
||||
for (const parsedOutput of parsedOutputs) {
|
||||
if (parsedOutput.agentSessionId) {
|
||||
session.agentSessionId = parsedOutput.agentSessionId;
|
||||
}
|
||||
|
||||
const line = codexFileChangeTracker
|
||||
? await codexFileChangeTracker.track(parsedOutput.payload)
|
||||
: parsedOutput.payload;
|
||||
|
||||
this.broadcast('heteroAgentRawLine', {
|
||||
line,
|
||||
const events = await produce();
|
||||
// Adapter-extracted CC/Codex session id powers `--resume` on the
|
||||
// next prompt; surface it through the existing `getSessionInfo`
|
||||
// IPC by mirroring the freshest value onto the session record.
|
||||
if (pipeline.sessionId && pipeline.sessionId !== session.agentSessionId) {
|
||||
session.agentSessionId = pipeline.sessionId;
|
||||
}
|
||||
for (const event of events) {
|
||||
this.broadcast('heteroAgentEvent', {
|
||||
event,
|
||||
sessionId: session.sessionId,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Failed to broadcast parsed agent output:', error);
|
||||
logger.error('Failed to broadcast agent stream batch:', error);
|
||||
});
|
||||
};
|
||||
|
||||
// Stream stdout events as raw provider payloads to Renderer.
|
||||
// Stream stdout events through the producer pipeline.
|
||||
const stdout = proc.stdout as Readable;
|
||||
stdout.on('data', (chunk: Buffer) => {
|
||||
void this.appendCliTraceFile(traceSession, 'stdout.jsonl', chunk);
|
||||
broadcastParsedOutputs(streamProcessor.push(chunk));
|
||||
broadcastPipelineBatch(() => pipeline.push(chunk));
|
||||
});
|
||||
stdout.on('end', () => {
|
||||
broadcastParsedOutputs(streamProcessor.flush());
|
||||
broadcastPipelineBatch(() => pipeline.flush());
|
||||
});
|
||||
|
||||
// Capture stderr
|
||||
@@ -915,44 +822,59 @@ export default class HeterogeneousAgentCtr extends ControllerModule {
|
||||
});
|
||||
|
||||
proc.on('exit', (code, signal) => {
|
||||
void stdoutBroadcastQueue.finally(async () => {
|
||||
void this.writeCliTraceJson(traceSession, 'exit.json', {
|
||||
code,
|
||||
finishedAt: new Date().toISOString(),
|
||||
signal,
|
||||
});
|
||||
await this.flushCliTrace(traceSession);
|
||||
|
||||
logger.info('Agent process exited:', { code, sessionId: session.sessionId, signal });
|
||||
session.process = undefined;
|
||||
|
||||
// If *we* killed it (cancel / stop / before-quit), treat the non-zero
|
||||
// exit as a clean shutdown — surfacing it as an error would make a
|
||||
// user-initiated cancel look like an agent failure, and an Electron
|
||||
// shutdown affecting OTHER running CC sessions would pollute their
|
||||
// topics with a misleading "Agent exited with code 143" message.
|
||||
if (session.cancelledByUs) {
|
||||
this.broadcast('heteroAgentSessionComplete', { sessionId: session.sessionId });
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (code === 0) {
|
||||
this.broadcast('heteroAgentSessionComplete', { sessionId: session.sessionId });
|
||||
resolve();
|
||||
} else {
|
||||
const stderrOutput = stderrChunks.join('').trim();
|
||||
const errorMsg = this.getExitErrorMessage(code, session, stderrOutput);
|
||||
const sessionError = this.getSessionErrorPayload(errorMsg, session);
|
||||
this.broadcast('heteroAgentSessionError', {
|
||||
error: sessionError,
|
||||
sessionId: session.sessionId,
|
||||
});
|
||||
reject(
|
||||
new Error(typeof sessionError === 'string' ? sessionError : sessionError.message),
|
||||
);
|
||||
}
|
||||
// Node may emit `'exit'` BEFORE stdio finishes draining (documented:
|
||||
// child_process docs note "stdio streams might still be open" at exit
|
||||
// time). Wait for stdout to fully end/close so the `stdout.on('end')`
|
||||
// handler has scheduled `pipeline.flush()` onto `stdoutBroadcastQueue`,
|
||||
// THEN wait for the queue itself to settle. Without this two-step
|
||||
// gate, trailing flushed events (final synthesized tool_end /
|
||||
// tool_result) would race against — and lose to — the
|
||||
// `heteroAgentSessionComplete` broadcast, leaving renderer-side
|
||||
// persistence to finalize on incomplete state.
|
||||
const stdoutDrained = streamFinished(stdout, { writable: false }).catch(() => {
|
||||
/* end / close / error are all "done"; we still want to settle. */
|
||||
});
|
||||
|
||||
void stdoutDrained
|
||||
.then(() => stdoutBroadcastQueue)
|
||||
.finally(async () => {
|
||||
void this.writeCliTraceJson(traceSession, 'exit.json', {
|
||||
code,
|
||||
finishedAt: new Date().toISOString(),
|
||||
signal,
|
||||
});
|
||||
await this.flushCliTrace(traceSession);
|
||||
|
||||
logger.info('Agent process exited:', { code, sessionId: session.sessionId, signal });
|
||||
session.process = undefined;
|
||||
|
||||
// If *we* killed it (cancel / stop / before-quit), treat the non-zero
|
||||
// exit as a clean shutdown — surfacing it as an error would make a
|
||||
// user-initiated cancel look like an agent failure, and an Electron
|
||||
// shutdown affecting OTHER running CC sessions would pollute their
|
||||
// topics with a misleading "Agent exited with code 143" message.
|
||||
if (session.cancelledByUs) {
|
||||
this.broadcast('heteroAgentSessionComplete', { sessionId: session.sessionId });
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (code === 0) {
|
||||
this.broadcast('heteroAgentSessionComplete', { sessionId: session.sessionId });
|
||||
resolve();
|
||||
} else {
|
||||
const stderrOutput = stderrChunks.join('').trim();
|
||||
const errorMsg = this.getExitErrorMessage(code, session, stderrOutput);
|
||||
const sessionError = this.getSessionErrorPayload(errorMsg, session);
|
||||
this.broadcast('heteroAgentSessionError', {
|
||||
error: sessionError,
|
||||
sessionId: session.sessionId,
|
||||
});
|
||||
reject(
|
||||
new Error(typeof sessionError === 'string' ? sessionError : sessionError.message),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
} from '@lobechat/electron-client-ipc';
|
||||
import {
|
||||
editLocalFile,
|
||||
expandTilde,
|
||||
listLocalFiles,
|
||||
moveLocalFiles,
|
||||
readLocalFile,
|
||||
@@ -574,7 +575,7 @@ export default class LocalFileCtr extends ControllerModule {
|
||||
*/
|
||||
@IpcMethod()
|
||||
async handleLocalFilesSearch(params: LocalSearchFilesParams): Promise<FileResult[]> {
|
||||
const effectiveDirectory = params.directory ?? params.scope;
|
||||
const effectiveDirectory = expandTilde(params.directory ?? params.scope);
|
||||
|
||||
logger.debug('Received file search request:', {
|
||||
directory: params.directory,
|
||||
|
||||
@@ -19,6 +19,26 @@ export default class TrayMenuCtr extends ControllerModule {
|
||||
mainWindow.toggleVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the application tray is visible.
|
||||
*/
|
||||
@IpcMethod()
|
||||
getAppTrayVisible(): boolean {
|
||||
return this.app.storeManager.get('appTrayVisible', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist and apply application tray visibility.
|
||||
*/
|
||||
@IpcMethod()
|
||||
setAppTrayVisible(visible: boolean) {
|
||||
logger.debug(`Set app tray visibility: ${visible}`);
|
||||
this.app.storeManager.set('appTrayVisible', visible);
|
||||
this.app.trayManager.setAppTrayVisible(visible);
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Show tray balloon notification
|
||||
* @param options Balloon options
|
||||
|
||||
@@ -433,18 +433,23 @@ describe('GatewayConnectionCtr', () => {
|
||||
}
|
||||
|
||||
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],
|
||||
['readFile', 'readFile', mockLocalFileCtr],
|
||||
['listFiles', 'listLocalFiles', mockLocalFileCtr],
|
||||
['moveFiles', 'handleMoveFiles', mockLocalFileCtr],
|
||||
['searchFiles', 'handleLocalFilesSearch', mockLocalFileCtr],
|
||||
['writeFile', 'handleWriteFile', mockLocalFileCtr],
|
||||
['editFile', 'handleEditFile', mockLocalFileCtr],
|
||||
['globFiles', 'handleGlobFiles', mockLocalFileCtr],
|
||||
['grepContent', 'handleGrepContent', mockLocalFileCtr],
|
||||
['runCommand', 'handleRunCommand', mockShellCommandCtr],
|
||||
['getCommandOutput', 'handleGetCommandOutput', mockShellCommandCtr],
|
||||
['killCommand', 'handleKillCommand', mockShellCommandCtr],
|
||||
// Legacy aliases — older Gateway versions may still send the long form.
|
||||
// `renameLocalFile` is kept even though the new surface drops rename.
|
||||
['readLocalFile', 'readFile', mockLocalFileCtr],
|
||||
['listLocalFiles', 'listLocalFiles', mockLocalFileCtr],
|
||||
['writeLocalFile', 'handleWriteFile', mockLocalFileCtr],
|
||||
['renameLocalFile', 'handleRenameFile', mockLocalFileCtr],
|
||||
] as const)('should route %s to %s', async (apiName, methodName, controller) => {
|
||||
const client = await connectAndOpen();
|
||||
const args = { test: 'arg' };
|
||||
@@ -470,7 +475,7 @@ describe('GatewayConnectionCtr', () => {
|
||||
});
|
||||
const client = await connectAndOpen();
|
||||
|
||||
client.simulateToolCallRequest('readLocalFile', { path: '/a.txt' }, 'req-42');
|
||||
client.simulateToolCallRequest('readFile', { path: '/a.txt' }, 'req-42');
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
|
||||
expect(client.sendToolCallResponse).toHaveBeenCalledWith({
|
||||
@@ -497,7 +502,7 @@ describe('GatewayConnectionCtr', () => {
|
||||
vi.mocked(mockLocalFileCtr.readFile).mockRejectedValueOnce(new Error('File not found'));
|
||||
const client = await connectAndOpen();
|
||||
|
||||
client.simulateToolCallRequest('readLocalFile', { path: '/missing' }, 'req-err');
|
||||
client.simulateToolCallRequest('readFile', { path: '/missing' }, 'req-err');
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
|
||||
expect(client.sendToolCallResponse).toHaveBeenCalledWith({
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { dequoteGitPath, quoteGitPath } from '../GitCtr';
|
||||
|
||||
vi.mock('@/utils/logger', () => ({
|
||||
createLogger: () => ({
|
||||
debug: vi.fn(),
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('quoteGitPath', () => {
|
||||
it('leaves plain ASCII paths unquoted (including spaces)', () => {
|
||||
expect(quoteGitPath('a/', 'src/foo.ts')).toBe('a/src/foo.ts');
|
||||
expect(quoteGitPath('b/', 'src/foo bar.ts')).toBe('b/src/foo bar.ts');
|
||||
expect(quoteGitPath('a/', 'with-dash_and.underscore')).toBe('a/with-dash_and.underscore');
|
||||
});
|
||||
|
||||
it('C-style escapes TAB / LF / CR / quote / backslash', () => {
|
||||
expect(quoteGitPath('b/', 'with\ttab.txt')).toBe('"b/with\\ttab.txt"');
|
||||
expect(quoteGitPath('b/', 'with\nlf.txt')).toBe('"b/with\\nlf.txt"');
|
||||
expect(quoteGitPath('b/', 'with\rcr.txt')).toBe('"b/with\\rcr.txt"');
|
||||
expect(quoteGitPath('b/', 'with"quote.txt')).toBe('"b/with\\"quote.txt"');
|
||||
expect(quoteGitPath('b/', 'with\\backslash.txt')).toBe('"b/with\\\\backslash.txt"');
|
||||
});
|
||||
|
||||
it('octal-escapes other control bytes (NUL, 0x1F, DEL)', () => {
|
||||
expect(quoteGitPath('a/', 'nul\x00here')).toBe('"a/nul\\000here"');
|
||||
expect(quoteGitPath('a/', 'unit\x1Fsep')).toBe('"a/unit\\037sep"');
|
||||
expect(quoteGitPath('a/', 'del\x7Fchar')).toBe('"a/del\\177char"');
|
||||
});
|
||||
|
||||
it('puts the prefix inside the quotes', () => {
|
||||
// Real git output for `git diff` of a tab-containing file:
|
||||
// diff --git "a/with\there" "b/with\there"
|
||||
expect(quoteGitPath('a/', 'with\there')).toBe('"a/with\\there"');
|
||||
expect(quoteGitPath('b/', 'with\there')).toBe('"b/with\\there"');
|
||||
});
|
||||
|
||||
it('round-trips through dequoteGitPath for problem characters', () => {
|
||||
const cases = [
|
||||
'with\ttab.txt',
|
||||
'with\nlf.txt',
|
||||
'with\rcr.txt',
|
||||
'with"quote.txt',
|
||||
'with\\backslash.txt',
|
||||
'nul\x00inside',
|
||||
'mix\t"of\\everything\n',
|
||||
];
|
||||
for (const original of cases) {
|
||||
const quoted = quoteGitPath('b/', original);
|
||||
// Strip the surrounding quotes + b/ prefix, then de-escape.
|
||||
expect(quoted.startsWith('"b/')).toBe(true);
|
||||
expect(quoted.endsWith('"')).toBe(true);
|
||||
const stripped = quoted.slice(1, -1).slice('b/'.length);
|
||||
expect(dequoteGitPath(stripped)).toBe(original);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('dequoteGitPath', () => {
|
||||
it('decodes named C-style escapes', () => {
|
||||
expect(dequoteGitPath('with\\ttab')).toBe('with\ttab');
|
||||
expect(dequoteGitPath('with\\nlf')).toBe('with\nlf');
|
||||
expect(dequoteGitPath('with\\rcr')).toBe('with\rcr');
|
||||
expect(dequoteGitPath('with\\"quote')).toBe('with"quote');
|
||||
expect(dequoteGitPath('with\\\\bs')).toBe('with\\bs');
|
||||
});
|
||||
|
||||
it('decodes 3-digit octal escapes', () => {
|
||||
expect(dequoteGitPath('nul\\000here')).toBe('nul\x00here');
|
||||
expect(dequoteGitPath('unit\\037sep')).toBe('unit\x1Fsep');
|
||||
expect(dequoteGitPath('del\\177char')).toBe('del\x7Fchar');
|
||||
});
|
||||
|
||||
it('leaves unescaped chars alone', () => {
|
||||
expect(dequoteGitPath('plain ascii here')).toBe('plain ascii here');
|
||||
});
|
||||
});
|
||||
@@ -11,8 +11,12 @@ import HeterogeneousAgentCtr from '../HeterogeneousAgentCtr';
|
||||
|
||||
const FAKE_DESKTOP_PATH = '/Users/fake/Desktop';
|
||||
|
||||
const { mockGetAllWindows } = vi.hoisted(() => ({
|
||||
mockGetAllWindows: vi.fn<() => any[]>(() => []),
|
||||
}));
|
||||
|
||||
vi.mock('electron', () => ({
|
||||
BrowserWindow: { getAllWindows: () => [] },
|
||||
BrowserWindow: { getAllWindows: () => mockGetAllWindows() },
|
||||
app: {
|
||||
getPath: vi.fn((name: string) => (name === 'desktop' ? FAKE_DESKTOP_PATH : `/fake/${name}`)),
|
||||
isPackaged: false,
|
||||
@@ -114,13 +118,24 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
await rm(appStoragePath, { force: true, recursive: true });
|
||||
});
|
||||
|
||||
describe('resolveImage', () => {
|
||||
describe('image cache (delegates to shared `normalizeImage`)', () => {
|
||||
// Image fetch + cache moved to `@lobechat/heterogeneous-agents/spawn`'s
|
||||
// `normalizeImage`. The desktop controller passes its own cacheDir so the
|
||||
// path-traversal invariant — id segments like `../../foo` MUST be hashed,
|
||||
// never used as path segments — is enforced by the shared helper. Verify
|
||||
// that invariant against the same cacheDir the controller would use.
|
||||
const fixtureCacheDir = (storage: string) => path.join(storage, 'heteroAgent/files');
|
||||
const importNormalize = async () => {
|
||||
const { mkdir } = await import('node:fs/promises');
|
||||
const mod = await import('@lobechat/heterogeneous-agents/spawn');
|
||||
return { mkdir, normalizeImage: mod.normalizeImage };
|
||||
};
|
||||
|
||||
it('stores traversal-looking ids inside the cache root via a stable hash key', async () => {
|
||||
const ctr = new HeterogeneousAgentCtr({
|
||||
appStoragePath,
|
||||
storeManager: { get: vi.fn() },
|
||||
} as any);
|
||||
const cacheDir = path.join(appStoragePath, 'heteroAgent/files');
|
||||
const { mkdir, normalizeImage } = await importNormalize();
|
||||
const cacheDir = fixtureCacheDir(appStoragePath);
|
||||
await mkdir(cacheDir, { recursive: true });
|
||||
|
||||
const escapedTargetName = `${path.basename(appStoragePath)}-outside-storage`;
|
||||
const escapePath = path.join(cacheDir, `../../../${escapedTargetName}`);
|
||||
|
||||
@@ -130,10 +145,14 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
// best-effort cleanup
|
||||
}
|
||||
|
||||
await (ctr as any).resolveImage({
|
||||
id: `../../../${escapedTargetName}`,
|
||||
url: 'data:text/plain;base64,T1VUU0lERQ==',
|
||||
});
|
||||
await normalizeImage(
|
||||
{
|
||||
id: `../../../${escapedTargetName}`,
|
||||
type: 'url',
|
||||
url: 'data:text/plain;base64,T1VUU0lERQ==',
|
||||
},
|
||||
{ cacheDir, fetcher: (async () => new Response('OUTSIDE', { status: 200 })) as any },
|
||||
);
|
||||
|
||||
const cacheEntries = await readdir(cacheDir);
|
||||
|
||||
@@ -149,11 +168,10 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
});
|
||||
|
||||
it('does not trust pre-seeded out-of-root traversal cache files as cache hits', async () => {
|
||||
const ctr = new HeterogeneousAgentCtr({
|
||||
appStoragePath,
|
||||
storeManager: { get: vi.fn() },
|
||||
} as any);
|
||||
const cacheDir = path.join(appStoragePath, 'heteroAgent/files');
|
||||
const { mkdir, normalizeImage } = await importNormalize();
|
||||
const cacheDir = fixtureCacheDir(appStoragePath);
|
||||
await mkdir(cacheDir, { recursive: true });
|
||||
|
||||
const traversalId = '../../preexisting-secret';
|
||||
const outOfRootDataPath = path.join(cacheDir, traversalId);
|
||||
const outOfRootMetaPath = path.join(cacheDir, `${traversalId}.meta`);
|
||||
@@ -164,13 +182,20 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
JSON.stringify({ id: traversalId, mimeType: 'text/plain' }),
|
||||
);
|
||||
|
||||
const result = await (ctr as any).resolveImage({
|
||||
id: traversalId,
|
||||
url: 'data:text/plain;base64,SUdOT1JFRA==',
|
||||
});
|
||||
const result = await normalizeImage(
|
||||
{ id: traversalId, type: 'url', url: 'data:text/plain;base64,SUdOT1JFRA==' },
|
||||
{
|
||||
cacheDir,
|
||||
fetcher: (async () =>
|
||||
new Response('IGNORED', {
|
||||
headers: { 'content-type': 'text/plain' },
|
||||
status: 200,
|
||||
})) as any,
|
||||
},
|
||||
);
|
||||
|
||||
expect(Buffer.from(result.buffer).toString('utf8')).toBe('IGNORED');
|
||||
expect(result.mimeType).toBe('text/plain');
|
||||
expect(result.mediaType).toBe('text/plain');
|
||||
await expect(readFile(outOfRootDataPath, 'utf8')).resolves.toBe('SECRET');
|
||||
});
|
||||
});
|
||||
@@ -199,7 +224,7 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
command: 'claude',
|
||||
...sessionOverrides,
|
||||
});
|
||||
await ctr.sendPrompt({ prompt, sessionId, ...sendPromptOverrides });
|
||||
await ctr.sendPrompt({ operationId: 'op-test', prompt, sessionId, ...sendPromptOverrides });
|
||||
|
||||
const { args: cliArgs, command, options } = spawnCalls[0];
|
||||
return { cliArgs, command, ctr, options, sessionId, writes };
|
||||
@@ -314,7 +339,7 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
command: 'codex',
|
||||
...sessionOverrides,
|
||||
});
|
||||
await ctr.sendPrompt({ prompt, sessionId, ...sendPromptOverrides });
|
||||
await ctr.sendPrompt({ operationId: 'op-test', prompt, sessionId, ...sendPromptOverrides });
|
||||
|
||||
const { args: cliArgs, command, options } = spawnCalls[0];
|
||||
return { cliArgs, command, ctr, options, sessionId, writes };
|
||||
@@ -332,9 +357,9 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
command: 'codex',
|
||||
});
|
||||
|
||||
await expect(ctr.sendPrompt({ prompt: 'hello', sessionId })).rejects.toThrow(
|
||||
'Codex CLI was not found',
|
||||
);
|
||||
await expect(
|
||||
ctr.sendPrompt({ operationId: 'op-test', prompt: 'hello', sessionId }),
|
||||
).rejects.toThrow('Codex CLI was not found');
|
||||
|
||||
expect(detect).toHaveBeenCalledWith('codex', true);
|
||||
expect(spawnCalls).toHaveLength(0);
|
||||
@@ -352,9 +377,9 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
command: 'claude',
|
||||
});
|
||||
|
||||
await expect(ctr.sendPrompt({ prompt: 'hello', sessionId })).rejects.toThrow(
|
||||
'Claude Code CLI was not found',
|
||||
);
|
||||
await expect(
|
||||
ctr.sendPrompt({ operationId: 'op-test', prompt: 'hello', sessionId }),
|
||||
).rejects.toThrow('Claude Code CLI was not found');
|
||||
|
||||
expect(detect).toHaveBeenCalledWith('claude', true);
|
||||
expect(spawnCalls).toHaveLength(0);
|
||||
@@ -390,9 +415,9 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
command: 'claude-alt',
|
||||
});
|
||||
|
||||
await expect(ctr.sendPrompt({ prompt: 'hello', sessionId })).rejects.toThrow(
|
||||
'Claude Code CLI was not found',
|
||||
);
|
||||
await expect(
|
||||
ctr.sendPrompt({ operationId: 'op-test', prompt: 'hello', sessionId }),
|
||||
).rejects.toThrow('Claude Code CLI was not found');
|
||||
|
||||
expect(detect).not.toHaveBeenCalled();
|
||||
expect(spawnCalls).toHaveLength(0);
|
||||
@@ -493,6 +518,7 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
await expect(
|
||||
ctr.sendPrompt({
|
||||
imageList,
|
||||
operationId: 'op-test',
|
||||
prompt: 'inspect the screenshots',
|
||||
sessionId,
|
||||
}),
|
||||
@@ -526,9 +552,9 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
command: 'codex',
|
||||
});
|
||||
|
||||
await expect(ctr.sendPrompt({ prompt: 'hello', sessionId })).rejects.toThrow(
|
||||
'Agent exited with code 1',
|
||||
);
|
||||
await expect(
|
||||
ctr.sendPrompt({ operationId: 'op-test', prompt: 'hello', sessionId }),
|
||||
).rejects.toThrow('Agent exited with code 1');
|
||||
});
|
||||
|
||||
it('uses codex exec resume syntax when continuing an existing thread', async () => {
|
||||
@@ -672,4 +698,108 @@ describe('HeterogeneousAgentCtr', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Node may emit `proc.on('exit')` BEFORE stdout fully drains (documented in
|
||||
* child_process docs as "stdio streams might still be open"). The phase 0
|
||||
* refactor moved adapter ownership to main, so renderer no longer flushes
|
||||
* its own adapter on session-complete — meaning trailing events from
|
||||
* `pipeline.flush()` (e.g. Codex's synthesized `tool_end` for unfinished
|
||||
* tool calls) would race against — and lose to — the
|
||||
* `heteroAgentSessionComplete` broadcast without an explicit gate.
|
||||
*
|
||||
* The fix in `proc.on('exit')` is to await stdout `'end'/'close'` (so the
|
||||
* `stdout.on('end')` handler can schedule `pipeline.flush()` onto the
|
||||
* broadcast queue), then drain the queue, then broadcast complete.
|
||||
*/
|
||||
describe('exit-before-end ordering (LOBE-8516 phase 0 race)', () => {
|
||||
let broadcasts: Array<{ channel: string; data: any }>;
|
||||
|
||||
beforeEach(() => {
|
||||
spawnCalls.length = 0;
|
||||
execFileMock.mockReset();
|
||||
broadcasts = [];
|
||||
mockGetAllWindows.mockImplementation(() => [
|
||||
{
|
||||
isDestroyed: () => false,
|
||||
webContents: {
|
||||
send: (channel: string, data: any) => broadcasts.push({ channel, data }),
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockGetAllWindows.mockReset();
|
||||
mockGetAllWindows.mockReturnValue([]);
|
||||
});
|
||||
|
||||
it('delivers pipeline.flush() events BEFORE heteroAgentSessionComplete even when proc exit precedes stdout end', async () => {
|
||||
// Codex `item.started` for a tool — adapter buffers it as a pending
|
||||
// tool call. On flush, adapter synthesizes a trailing `tool_end`. This
|
||||
// is exactly the kind of event the race would lose against complete.
|
||||
const itemStarted = `${JSON.stringify({
|
||||
item: {
|
||||
aggregated_output: '',
|
||||
command: 'echo hi',
|
||||
id: 'cmd-1',
|
||||
status: 'in_progress',
|
||||
type: 'command_execution',
|
||||
},
|
||||
type: 'item.started',
|
||||
})}\n`;
|
||||
const threadStarted = `${JSON.stringify({ thread_id: 't1', type: 'thread.started' })}\n`;
|
||||
|
||||
const proc = new EventEmitter() as any;
|
||||
const stdout = new PassThrough();
|
||||
const stderr = new PassThrough();
|
||||
proc.stdout = stdout;
|
||||
proc.stderr = stderr;
|
||||
proc.stdin = {
|
||||
end: vi.fn(),
|
||||
write: vi.fn((_chunk: any, cb?: () => void) => {
|
||||
cb?.();
|
||||
return true;
|
||||
}),
|
||||
};
|
||||
proc.kill = vi.fn();
|
||||
proc.killed = false;
|
||||
proc.__start = () => {
|
||||
setImmediate(() => {
|
||||
stdout.write(threadStarted);
|
||||
stdout.write(itemStarted);
|
||||
stderr.end();
|
||||
// ⚠️ Reproduce the documented Node race: emit exit BEFORE stdout
|
||||
// ends. Without the streamFinished gate in the controller, the
|
||||
// broadcast queue settles immediately (no flush queued yet) and
|
||||
// complete fires before the trailing tool_end ever broadcasts.
|
||||
proc.emit('exit', 0);
|
||||
setImmediate(() => stdout.end());
|
||||
});
|
||||
};
|
||||
nextFakeProc = proc;
|
||||
|
||||
const ctr = new HeterogeneousAgentCtr({
|
||||
appStoragePath,
|
||||
storeManager: { get: vi.fn() },
|
||||
} as any);
|
||||
const { sessionId } = await ctr.startSession({ agentType: 'codex', command: 'codex' });
|
||||
await ctr.sendPrompt({ operationId: 'op-test', prompt: 'hello', sessionId });
|
||||
|
||||
const events = broadcasts.filter((b) => b.channel === 'heteroAgentEvent');
|
||||
const completeIdx = broadcasts.findIndex((b) => b.channel === 'heteroAgentSessionComplete');
|
||||
const lastEventIdx = broadcasts.findLastIndex((b) => b.channel === 'heteroAgentEvent');
|
||||
|
||||
expect(completeIdx).toBeGreaterThan(-1);
|
||||
expect(events.length).toBeGreaterThan(0);
|
||||
// Every stream event must land before complete — no trailing events
|
||||
// sneak in after the renderer has been told the session is done.
|
||||
expect(lastEventIdx).toBeLessThan(completeIdx);
|
||||
|
||||
// Specifically: the synthesized tool_end for the pending command
|
||||
// execution (emitted only by adapter.flush()) is in the broadcast.
|
||||
const toolEnds = events.filter((b) => (b.data as any)?.event?.type === 'tool_end');
|
||||
expect(toolEnds.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,13 +40,21 @@ const mockDisplayBalloon = vi.fn();
|
||||
const mockUpdateIcon = vi.fn();
|
||||
const mockUpdateTooltip = vi.fn();
|
||||
const mockGetMainTray = vi.fn();
|
||||
const mockSetAppTrayVisible = vi.fn();
|
||||
const mockStoreGet = vi.fn(() => true);
|
||||
const mockStoreSet = vi.fn();
|
||||
|
||||
const mockApp = {
|
||||
browserManager: {
|
||||
getMainWindow: mockGetMainWindow,
|
||||
},
|
||||
storeManager: {
|
||||
get: mockStoreGet,
|
||||
set: mockStoreSet,
|
||||
},
|
||||
trayManager: {
|
||||
getMainTray: mockGetMainTray,
|
||||
setAppTrayVisible: mockSetAppTrayVisible,
|
||||
},
|
||||
} as unknown as App;
|
||||
|
||||
@@ -58,9 +66,31 @@ describe('TrayMenuCtr', () => {
|
||||
ipcMainHandleMock.mockClear();
|
||||
// Reset mockedTray for each test
|
||||
mockGetMainTray.mockReset();
|
||||
mockStoreGet.mockReturnValue(true);
|
||||
trayMenuCtr = new TrayMenuCtr(mockApp);
|
||||
});
|
||||
|
||||
describe('getAppTrayVisible', () => {
|
||||
it('should return stored app tray visibility', () => {
|
||||
mockStoreGet.mockReturnValue(false);
|
||||
|
||||
const result = trayMenuCtr.getAppTrayVisible();
|
||||
|
||||
expect(mockStoreGet).toHaveBeenCalledWith('appTrayVisible', true);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setAppTrayVisible', () => {
|
||||
it('should persist and apply app tray visibility', () => {
|
||||
const result = trayMenuCtr.setAppTrayVisible(false);
|
||||
|
||||
expect(mockStoreSet).toHaveBeenCalledWith('appTrayVisible', false);
|
||||
expect(mockSetAppTrayVisible).toHaveBeenCalledWith(false);
|
||||
expect(result).toEqual({ success: true });
|
||||
});
|
||||
});
|
||||
|
||||
// Restore platform settings after all tests complete
|
||||
afterAll(() => {
|
||||
// Restore the original platform
|
||||
|
||||
@@ -39,6 +39,12 @@ export class TrayManager {
|
||||
initializeTrays() {
|
||||
logger.debug('Initialize application tray');
|
||||
|
||||
if (!this.app.storeManager.get('appTrayVisible', true)) {
|
||||
logger.debug('Application tray is disabled by user settings');
|
||||
this.destroyAll();
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize main tray
|
||||
const mainTray = this.initializeMainTray();
|
||||
|
||||
@@ -58,6 +64,19 @@ export class TrayManager {
|
||||
return this.retrieveByIdentifier('main');
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the application tray at runtime.
|
||||
*/
|
||||
setAppTrayVisible(visible: boolean) {
|
||||
logger.debug(`Set application tray visible: ${visible}`);
|
||||
|
||||
if (visible) {
|
||||
this.initializeTrays();
|
||||
} else {
|
||||
this.destroyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize main tray. On macOS we ship a template image (black + alpha)
|
||||
* so the system recolors it automatically for light / dark menu bars.
|
||||
|
||||
@@ -55,6 +55,9 @@ describe('TrayManager', () => {
|
||||
menuManager: {
|
||||
buildTrayMenu: vi.fn(() => ({ _mockMenu: true }) as any),
|
||||
},
|
||||
storeManager: {
|
||||
get: vi.fn(() => true),
|
||||
},
|
||||
} as unknown as App;
|
||||
|
||||
// Mock Tray constructor
|
||||
@@ -93,6 +96,15 @@ describe('TrayManager', () => {
|
||||
expect(mockApp.menuManager.buildTrayMenu).toHaveBeenCalled();
|
||||
expect(mockTray.setMenu).toHaveBeenCalledWith({ _mockMenu: true });
|
||||
});
|
||||
|
||||
it('should skip tray initialization when app tray is disabled', () => {
|
||||
vi.mocked(mockApp.storeManager.get).mockReturnValue(false);
|
||||
|
||||
trayManager.initializeTrays();
|
||||
|
||||
expect(Tray).not.toHaveBeenCalled();
|
||||
expect(trayManager.trays.size).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('initializeMainTray', () => {
|
||||
@@ -273,6 +285,24 @@ describe('TrayManager', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('setAppTrayVisible', () => {
|
||||
it('should initialize trays when visible is true', () => {
|
||||
trayManager.setAppTrayVisible(true);
|
||||
|
||||
expect(Tray).toHaveBeenCalled();
|
||||
expect(trayManager.trays.has('main')).toBe(true);
|
||||
});
|
||||
|
||||
it('should destroy all trays when visible is false', () => {
|
||||
trayManager.initializeTrays();
|
||||
|
||||
trayManager.setAppTrayVisible(false);
|
||||
|
||||
expect(mockTray.destroy).toHaveBeenCalled();
|
||||
expect(trayManager.trays.size).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('retrieveOrInitialize (private method)', () => {
|
||||
it('should create new tray when it does not exist', () => {
|
||||
const options = {
|
||||
|
||||
@@ -75,6 +75,7 @@ const menu = {
|
||||
'tray.open': 'Open {{appName}}',
|
||||
'tray.quickChat': 'Quick Chat',
|
||||
'tray.quit': 'Quit',
|
||||
'tray.settings': 'Settings',
|
||||
'tray.show': 'Show {{appName}}',
|
||||
'view.forceReload': 'Force Reload',
|
||||
'view.reload': 'Reload',
|
||||
|
||||
@@ -63,7 +63,9 @@ const createMockApp = () => {
|
||||
'dev.devPanel': 'Dev Panel',
|
||||
'tray.openMiniToolbar': 'Quick Composer',
|
||||
'tray.open': `Open ${params?.appName || 'App'}`,
|
||||
'tray.quickChat': 'Quick Chat',
|
||||
'tray.quit': 'Quit',
|
||||
'tray.settings': 'Settings',
|
||||
};
|
||||
return translations[key] || key;
|
||||
});
|
||||
@@ -197,6 +199,7 @@ describe('LinuxMenu', () => {
|
||||
const template = (Menu.buildFromTemplate as any).mock.calls[0][0];
|
||||
expect(template.length).toBeGreaterThan(0);
|
||||
expect(template.some((item: any) => item.label?.includes('Open'))).toBe(true);
|
||||
expect(template.some((item: any) => item.label === 'Settings')).toBe(true);
|
||||
expect(template.some((item: any) => item.label === 'Quit')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -466,7 +466,7 @@ export class LinuxMenu extends BaseMenuPlatform implements IMenuPlatform {
|
||||
{ type: 'separator' },
|
||||
{
|
||||
click: () => this.app.browserManager.retrieveByIdentifier('settings').show(),
|
||||
label: t('file.preferences'),
|
||||
label: t('tray.settings'),
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ label: t('tray.quit'), role: 'quit' },
|
||||
|
||||
@@ -31,6 +31,19 @@ vi.mock('electron', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('electron-is', () => ({
|
||||
macOS: vi.fn(() => true),
|
||||
}));
|
||||
|
||||
vi.mock('@/utils/logger', () => ({
|
||||
createLogger: () => ({
|
||||
debug: vi.fn(),
|
||||
error: vi.fn(),
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mock isDev
|
||||
vi.mock('@/const/env', () => ({
|
||||
isDev: false,
|
||||
@@ -177,6 +190,7 @@ describe('MacOSMenu', () => {
|
||||
const template = (Menu.buildFromTemplate as any).mock.calls[0][0];
|
||||
expect(template.length).toBeGreaterThan(0);
|
||||
expect(template.some((item: any) => item.label?.includes('Show'))).toBe(true);
|
||||
expect(template.some((item: any) => item.label === 'Settings')).toBe(true);
|
||||
expect(template.some((item: any) => item.label === 'Quit')).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
@@ -694,7 +694,7 @@ export class MacOSMenu extends BaseMenuPlatform implements IMenuPlatform {
|
||||
mainWindow.show();
|
||||
mainWindow.broadcast('navigate', { path: '/settings' });
|
||||
},
|
||||
label: t('file.preferences'),
|
||||
label: t('tray.settings'),
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ label: t('tray.quit'), role: 'quit' },
|
||||
|
||||
@@ -58,7 +58,9 @@ const createMockApp = () => {
|
||||
'dev.devPanel': 'Dev Panel',
|
||||
'tray.openMiniToolbar': 'Quick Composer',
|
||||
'tray.open': `Open ${params?.appName || 'App'}`,
|
||||
'tray.quickChat': 'Quick Chat',
|
||||
'tray.quit': 'Quit',
|
||||
'tray.settings': 'Settings',
|
||||
};
|
||||
return translations[key] || key;
|
||||
});
|
||||
@@ -179,6 +181,7 @@ describe('WindowsMenu', () => {
|
||||
const template = (Menu.buildFromTemplate as any).mock.calls[0][0];
|
||||
expect(template.length).toBeGreaterThan(0);
|
||||
expect(template.some((item: any) => item.label?.includes('Open'))).toBe(true);
|
||||
expect(template.some((item: any) => item.label === 'Settings')).toBe(true);
|
||||
expect(template.some((item: any) => item.label === 'Quit')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -473,7 +473,7 @@ export class WindowsMenu extends BaseMenuPlatform implements IMenuPlatform {
|
||||
{ type: 'separator' },
|
||||
{
|
||||
click: () => this.app.browserManager.retrieveByIdentifier('settings').show(),
|
||||
label: t('file.preferences'),
|
||||
label: t('tray.settings'),
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ label: t('tray.quit'), role: 'quit' },
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { buildFilenameKeywordExpression } from '../impl/macOS';
|
||||
|
||||
vi.mock('@/utils/logger', () => ({
|
||||
createLogger: () => ({
|
||||
debug: vi.fn(),
|
||||
error: vi.fn(),
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('buildFilenameKeywordExpression', () => {
|
||||
it('produces a single substring term for one keyword', () => {
|
||||
expect(buildFilenameKeywordExpression('package.json')).toBe(
|
||||
'kMDItemFSName == "*package.json*"cd',
|
||||
);
|
||||
});
|
||||
|
||||
it('splits whitespace-separated keywords into AND-ed substring terms', () => {
|
||||
// Critical fix: a free-form keyword string from the LLM (e.g. "LobeHub
|
||||
// Financial Statement") used to require that exact phrase to appear in the
|
||||
// filename. Real files reorder words and use _/-/. as separators, so the
|
||||
// literal phrase almost never matched. AND-ing per-token substrings keeps
|
||||
// each token literal but removes the order constraint.
|
||||
expect(buildFilenameKeywordExpression('LobeHub Financial Statement')).toBe(
|
||||
'(kMDItemFSName == "*LobeHub*"cd && kMDItemFSName == "*Financial*"cd && kMDItemFSName == "*Statement*"cd)',
|
||||
);
|
||||
});
|
||||
|
||||
it('collapses repeated whitespace and trims surrounding spaces', () => {
|
||||
expect(buildFilenameKeywordExpression(' foo \t\n bar ')).toBe(
|
||||
'(kMDItemFSName == "*foo*"cd && kMDItemFSName == "*bar*"cd)',
|
||||
);
|
||||
});
|
||||
|
||||
it('escapes embedded double quotes in each token', () => {
|
||||
expect(buildFilenameKeywordExpression('foo "bar" baz')).toBe(
|
||||
'(kMDItemFSName == "*foo*"cd && kMDItemFSName == "*\\"bar\\"*"cd && kMDItemFSName == "*baz*"cd)',
|
||||
);
|
||||
});
|
||||
|
||||
it('returns an empty string when keywords are blank', () => {
|
||||
expect(buildFilenameKeywordExpression('')).toBe('');
|
||||
expect(buildFilenameKeywordExpression(' \t ')).toBe('');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { LinuxSearchServiceImpl } from '../impl/linux';
|
||||
|
||||
vi.mock('node:os', () => ({
|
||||
homedir: vi.fn().mockReturnValue('/Users/test-home'),
|
||||
platform: vi.fn().mockReturnValue('linux'),
|
||||
}));
|
||||
|
||||
vi.mock('@/utils/logger', () => ({
|
||||
createLogger: () => ({
|
||||
debug: vi.fn(),
|
||||
error: vi.fn(),
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
const fgMock = vi.fn();
|
||||
vi.mock('fast-glob', () => ({
|
||||
default: (...args: unknown[]) => fgMock(...args),
|
||||
}));
|
||||
|
||||
const execaMock = vi.fn();
|
||||
vi.mock('execa', () => ({
|
||||
execa: (...args: unknown[]) => execaMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock('node:fs/promises', () => ({
|
||||
stat: vi.fn().mockResolvedValue({
|
||||
atime: new Date(),
|
||||
birthtime: new Date(),
|
||||
isDirectory: () => false,
|
||||
mtime: new Date(),
|
||||
size: 0,
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('UnixFileSearch glob fallback root', () => {
|
||||
beforeEach(() => {
|
||||
fgMock.mockReset();
|
||||
execaMock.mockReset();
|
||||
// Force the Unix tool selection to fall through to fast-glob so we
|
||||
// don't have to mock fd/find availability checks.
|
||||
execaMock.mockRejectedValue(new Error('command not found'));
|
||||
fgMock.mockResolvedValue([]);
|
||||
});
|
||||
|
||||
it('runs glob inside the user home directory when no scope is provided', async () => {
|
||||
// Regression: previously fell back to process.cwd(), which inside a
|
||||
// packaged Electron app is the bundle path — making `**/*foo*` searches
|
||||
// effectively look at nothing user-visible.
|
||||
const impl = new LinuxSearchServiceImpl();
|
||||
await impl.glob({ pattern: '**/*report*' });
|
||||
|
||||
expect(fgMock).toHaveBeenCalledTimes(1);
|
||||
const [pattern, options] = fgMock.mock.calls[0] as [string, { cwd: string }];
|
||||
expect(pattern).toBe('**/*report*');
|
||||
expect(options.cwd).toBe('/Users/test-home');
|
||||
});
|
||||
|
||||
it('honors an explicit scope over the home-directory fallback', async () => {
|
||||
const impl = new LinuxSearchServiceImpl();
|
||||
await impl.glob({ pattern: '**/*.ts', scope: '/Users/test-home/Downloads' });
|
||||
|
||||
const [, options] = fgMock.mock.calls[0] as [string, { cwd: string }];
|
||||
expect(options.cwd).toBe('/Users/test-home/Downloads');
|
||||
});
|
||||
});
|
||||
@@ -13,6 +13,29 @@ import { UnixFileSearch } from './unix';
|
||||
|
||||
const logger = createLogger('module:FileSearch:macOS');
|
||||
|
||||
/**
|
||||
* Build the kMDItemFSName expression for a free-form keyword string.
|
||||
*
|
||||
* Splits on whitespace and ANDs each token as a case/diacritic-insensitive
|
||||
* substring match, so "Foo Bar" matches both `Bar_Foo.pdf` and `Foo Bar.pdf`
|
||||
* — instead of requiring the literal phrase "Foo Bar" to appear.
|
||||
*
|
||||
* Returns an empty string when the keywords contain no usable token.
|
||||
*/
|
||||
export const buildFilenameKeywordExpression = (keywords: string): string => {
|
||||
const tokens = keywords
|
||||
.trim()
|
||||
.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.map((token) => token.replaceAll('"', '\\"'));
|
||||
|
||||
if (tokens.length === 0) return '';
|
||||
|
||||
const term = (token: string) => `kMDItemFSName == "*${token}*"cd`;
|
||||
if (tokens.length === 1) return term(tokens[0]);
|
||||
return `(${tokens.map(term).join(' && ')})`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fallback tool type for macOS file search
|
||||
* Priority: mdfind > fd > find > fast-glob
|
||||
@@ -95,7 +118,16 @@ export class MacOSSearchServiceImpl extends UnixFileSearch {
|
||||
* Search using Spotlight (mdfind)
|
||||
*/
|
||||
private async searchWithSpotlight(options: SearchOptions): Promise<FileResult[]> {
|
||||
const { cmd, args, commandString } = this.buildSearchCommand(options);
|
||||
const { cmd, args, commandString, hasQuery } = this.buildSearchCommand(options);
|
||||
|
||||
// Spotlight (mdfind) requires a query expression; running it with only flags
|
||||
// (e.g. -onlyin) makes mdfind print its usage to stdout and we'd treat each
|
||||
// line as a fake file. Short-circuit to an empty result instead.
|
||||
if (!hasQuery) {
|
||||
logger.warn('Skipping mdfind: no keywords/contentContains/fileTypes/date filter provided');
|
||||
return [];
|
||||
}
|
||||
|
||||
logger.debug(`Executing command: ${commandString}`);
|
||||
|
||||
try {
|
||||
@@ -176,6 +208,7 @@ export class MacOSSearchServiceImpl extends UnixFileSearch {
|
||||
args: string[];
|
||||
cmd: string;
|
||||
commandString: string;
|
||||
hasQuery: boolean;
|
||||
} {
|
||||
const cmd = 'mdfind';
|
||||
const args: string[] = [];
|
||||
@@ -204,7 +237,7 @@ export class MacOSSearchServiceImpl extends UnixFileSearch {
|
||||
|
||||
if (options.keywords) {
|
||||
if (!options.keywords.includes('kMDItem')) {
|
||||
queryExpression = `kMDItemFSName == "*${options.keywords.replaceAll('"', '\\"')}*"cd`;
|
||||
queryExpression = buildFilenameKeywordExpression(options.keywords);
|
||||
} else {
|
||||
queryExpression = options.keywords;
|
||||
}
|
||||
@@ -271,13 +304,15 @@ export class MacOSSearchServiceImpl extends UnixFileSearch {
|
||||
}
|
||||
}
|
||||
|
||||
if (queryExpression) {
|
||||
const hasQuery = Boolean(queryExpression);
|
||||
|
||||
if (hasQuery) {
|
||||
args.push(queryExpression);
|
||||
}
|
||||
|
||||
const commandString = `${cmd} ${args.map((arg) => (arg.includes(' ') || arg.includes('*') ? `"${arg}"` : arg)).join(' ')}`;
|
||||
|
||||
return { args, cmd, commandString };
|
||||
return { args, cmd, commandString, hasQuery };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,7 +323,7 @@ export class MacOSSearchServiceImpl extends UnixFileSearch {
|
||||
options: SearchOptions,
|
||||
engine?: string,
|
||||
): Promise<FileResult[]> {
|
||||
const resultPromises = filePaths.map(async (filePath) => {
|
||||
const resultPromises = filePaths.map(async (filePath): Promise<FileResult | null> => {
|
||||
try {
|
||||
const stats = await stat(filePath);
|
||||
|
||||
@@ -313,23 +348,15 @@ export class MacOSSearchServiceImpl extends UnixFileSearch {
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.warn(`Error processing file stats for ${filePath}: ${(error as Error).message}`);
|
||||
return {
|
||||
contentType: 'unknown',
|
||||
createdTime: new Date(),
|
||||
engine,
|
||||
isDirectory: false,
|
||||
lastAccessTime: new Date(),
|
||||
modifiedTime: new Date(),
|
||||
name: path.basename(filePath),
|
||||
path: filePath,
|
||||
size: 0,
|
||||
type: path.extname(filePath).toLowerCase().replace('.', ''),
|
||||
};
|
||||
// Drop the row instead of fabricating a 0-byte placeholder. mdfind
|
||||
// occasionally returns non-path lines (e.g. usage text when the query
|
||||
// is malformed) which would otherwise render as phantom files.
|
||||
logger.warn(`Dropping unstattable search hit ${filePath}: ${(error as Error).message}`);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
let results = await Promise.all(resultPromises);
|
||||
let results = (await Promise.all(resultPromises)).filter((r): r is FileResult => r !== null);
|
||||
|
||||
if (options.sortBy) {
|
||||
results = this.sortResults(results, options.sortBy, options.sortDirection);
|
||||
|
||||
@@ -337,7 +337,7 @@ export abstract class UnixFileSearch extends BaseFileSearch {
|
||||
* @returns Glob results
|
||||
*/
|
||||
protected async globWithFd(params: GlobFilesParams): Promise<GlobFilesResult> {
|
||||
const searchPath = params.scope || process.cwd();
|
||||
const searchPath = params.scope || os.homedir() || process.cwd();
|
||||
const logPrefix = `[glob:fd: ${params.pattern}]`;
|
||||
|
||||
logger.debug(`${logPrefix} Starting fd glob`, { searchPath });
|
||||
@@ -393,7 +393,7 @@ export abstract class UnixFileSearch extends BaseFileSearch {
|
||||
* @returns Glob results
|
||||
*/
|
||||
protected async globWithFind(params: GlobFilesParams): Promise<GlobFilesResult> {
|
||||
const searchPath = params.scope || process.cwd();
|
||||
const searchPath = params.scope || os.homedir() || process.cwd();
|
||||
const logPrefix = `[glob:find: ${params.pattern}]`;
|
||||
|
||||
logger.debug(`${logPrefix} Starting find glob`, { searchPath });
|
||||
@@ -455,7 +455,7 @@ export abstract class UnixFileSearch extends BaseFileSearch {
|
||||
* @returns Glob results
|
||||
*/
|
||||
protected async globWithFastGlob(params: GlobFilesParams): Promise<GlobFilesResult> {
|
||||
const searchPath = params.scope || process.cwd();
|
||||
const searchPath = params.scope || os.homedir() || process.cwd();
|
||||
const logPrefix = `[glob:fast-glob: ${params.pattern}]`;
|
||||
|
||||
logger.debug(`${logPrefix} Starting fast-glob`, { searchPath });
|
||||
|
||||
@@ -335,7 +335,7 @@ export class WindowsSearchServiceImpl extends BaseFileSearch {
|
||||
* @returns Glob results
|
||||
*/
|
||||
private async globWithFd(params: GlobFilesParams): Promise<GlobFilesResult> {
|
||||
const searchPath = params.scope || process.cwd();
|
||||
const searchPath = params.scope || os.homedir() || process.cwd();
|
||||
const logPrefix = `[glob:fd: ${params.pattern}]`;
|
||||
|
||||
logger.debug(`${logPrefix} Starting fd glob`, { searchPath });
|
||||
@@ -390,7 +390,7 @@ export class WindowsSearchServiceImpl extends BaseFileSearch {
|
||||
* @returns Glob results
|
||||
*/
|
||||
private async globWithFastGlob(params: GlobFilesParams): Promise<GlobFilesResult> {
|
||||
const searchPath = params.scope || process.cwd();
|
||||
const searchPath = params.scope || os.homedir() || process.cwd();
|
||||
const logPrefix = `[glob:fast-glob: ${params.pattern}]`;
|
||||
|
||||
logger.debug(`${logPrefix} Starting fast-glob`, { searchPath });
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { JsonlStreamProcessor } from '../jsonlProcessor';
|
||||
import type { HeterogeneousAgentBuildPlanParams, HeterogeneousAgentDriver } from '../types';
|
||||
|
||||
const CLAUDE_CODE_BASE_ARGS = [
|
||||
@@ -32,10 +31,4 @@ export const claudeCodeDriver: HeterogeneousAgentDriver = {
|
||||
stdinPayload,
|
||||
};
|
||||
},
|
||||
createStreamProcessor() {
|
||||
return new JsonlStreamProcessor({
|
||||
extractSessionId: (payload) =>
|
||||
payload?.type === 'system' && payload?.subtype === 'init' ? payload?.session_id : undefined,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { JsonlStreamProcessor } from '../jsonlProcessor';
|
||||
import type { HeterogeneousAgentBuildPlanParams, HeterogeneousAgentDriver } from '../types';
|
||||
|
||||
const CODEX_REQUIRED_ARGS = ['--json', '--skip-git-repo-check'] as const;
|
||||
@@ -41,10 +40,4 @@ export const codexDriver: HeterogeneousAgentDriver = {
|
||||
stdinPayload: prompt,
|
||||
};
|
||||
},
|
||||
createStreamProcessor() {
|
||||
return new JsonlStreamProcessor({
|
||||
extractSessionId: (payload) =>
|
||||
payload?.type === 'thread.started' ? payload?.thread_id : undefined,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import type { HeterogeneousAgentParsedOutput, HeterogeneousAgentStreamProcessor } from './types';
|
||||
|
||||
export interface JsonlProcessorOptions {
|
||||
extractSessionId?: (payload: any) => string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses stdout as JSONL / NDJSON while tolerating non-JSON noise lines.
|
||||
* Different CLIs still end up sharing this framing logic even when the
|
||||
* payload schema differs.
|
||||
*/
|
||||
export class JsonlStreamProcessor implements HeterogeneousAgentStreamProcessor {
|
||||
private buffer = '';
|
||||
|
||||
constructor(private readonly options: JsonlProcessorOptions = {}) {}
|
||||
|
||||
push(chunk: Buffer | string): HeterogeneousAgentParsedOutput[] {
|
||||
this.buffer += chunk instanceof Buffer ? chunk.toString('utf8') : chunk;
|
||||
return this.drainCompleteLines();
|
||||
}
|
||||
|
||||
flush(): HeterogeneousAgentParsedOutput[] {
|
||||
const trailing = this.buffer.trim();
|
||||
this.buffer = '';
|
||||
|
||||
if (!trailing) return [];
|
||||
|
||||
try {
|
||||
return [this.toParsedOutput(JSON.parse(trailing))];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private drainCompleteLines(): HeterogeneousAgentParsedOutput[] {
|
||||
const lines = this.buffer.split('\n');
|
||||
this.buffer = lines.pop() || '';
|
||||
|
||||
const parsed: HeterogeneousAgentParsedOutput[] = [];
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) continue;
|
||||
|
||||
try {
|
||||
parsed.push(this.toParsedOutput(JSON.parse(trimmed)));
|
||||
} catch {
|
||||
// Ignore non-JSON stdout noise.
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
private toParsedOutput(payload: any): HeterogeneousAgentParsedOutput {
|
||||
return {
|
||||
agentSessionId: this.options.extractSessionId?.(payload),
|
||||
payload,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -24,19 +24,13 @@ export interface HeterogeneousAgentBuildPlanParams {
|
||||
resumeSessionId?: string;
|
||||
}
|
||||
|
||||
export interface HeterogeneousAgentParsedOutput {
|
||||
agentSessionId?: string;
|
||||
payload: any;
|
||||
}
|
||||
|
||||
export interface HeterogeneousAgentStreamProcessor {
|
||||
flush: () => HeterogeneousAgentParsedOutput[];
|
||||
push: (chunk: Buffer | string) => HeterogeneousAgentParsedOutput[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-agent CLI flag composition + stdin shape. Stream framing is no longer the
|
||||
* driver's concern — `AgentStreamPipeline` (`@lobechat/heterogeneous-agents/spawn`)
|
||||
* runs JSONL parsing + adapter conversion uniformly for every agent type.
|
||||
*/
|
||||
export interface HeterogeneousAgentDriver {
|
||||
buildSpawnPlan: (
|
||||
params: HeterogeneousAgentBuildPlanParams,
|
||||
) => Promise<HeterogeneousAgentBuildPlan>;
|
||||
createStreamProcessor: () => HeterogeneousAgentStreamProcessor;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
} from '@lobechat/electron-client-ipc';
|
||||
|
||||
export interface ElectronMainStore {
|
||||
appTrayVisible: boolean;
|
||||
dataSyncConfig: DataSyncConfig;
|
||||
encryptedTokens: {
|
||||
accessToken?: string;
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { resolveOverlayModelSelectionPayload, shouldShowOverlayModelSelector } from './ChatPanel';
|
||||
import { resolvePanelPlacement } from './panelPlacement';
|
||||
|
||||
describe('resolvePanelPlacement', () => {
|
||||
vi.mock('./chatPanel.css.ts', () => new Proxy({}, { get: (_, key) => String(key) }));
|
||||
|
||||
vi.mock('./cn', () => ({
|
||||
cn: (...classes: Array<string | false | null | undefined>) => classes.filter(Boolean).join(' '),
|
||||
}));
|
||||
|
||||
vi.mock('./Avatar', () => ({
|
||||
default: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/icons', () => ({
|
||||
ModelIcon: () => null,
|
||||
}));
|
||||
|
||||
describe('ChatPanel', () => {
|
||||
it('keeps the last selection placement while a reselection is in progress', () => {
|
||||
expect(
|
||||
resolvePanelPlacement({
|
||||
@@ -30,4 +45,43 @@ describe('resolvePanelPlacement', () => {
|
||||
width: 420,
|
||||
});
|
||||
});
|
||||
|
||||
it('hides the model selector and omits model payload for heterogeneous agents', () => {
|
||||
const heterogeneousAgent = {
|
||||
heterogeneousType: 'codex',
|
||||
id: 'agent-codex',
|
||||
title: 'Codex Agent',
|
||||
};
|
||||
|
||||
expect(shouldShowOverlayModelSelector(heterogeneousAgent)).toBe(false);
|
||||
expect(
|
||||
resolveOverlayModelSelectionPayload({
|
||||
agent: heterogeneousAgent,
|
||||
model: { id: 'gpt-4.1', provider: 'openai' },
|
||||
modelId: 'gpt-4.1',
|
||||
}),
|
||||
).toEqual({
|
||||
modelId: undefined,
|
||||
provider: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps the model selector and payload for regular agents', () => {
|
||||
const regularAgent = {
|
||||
id: 'agent-regular',
|
||||
title: 'Regular Agent',
|
||||
};
|
||||
|
||||
expect(shouldShowOverlayModelSelector(regularAgent)).toBe(true);
|
||||
expect(
|
||||
resolveOverlayModelSelectionPayload({
|
||||
agent: regularAgent,
|
||||
model: { id: 'gpt-4.1', provider: 'openai' },
|
||||
modelId: 'gpt-4.1',
|
||||
}),
|
||||
).toEqual({
|
||||
modelId: 'gpt-4.1',
|
||||
provider: 'openai',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -57,6 +57,25 @@ export interface ChatPanelProps {
|
||||
viewportWidth: number;
|
||||
}
|
||||
|
||||
export const shouldShowOverlayModelSelector = (agent?: ScreenCaptureAgentOption) =>
|
||||
!agent?.heterogeneousType;
|
||||
|
||||
export const resolveOverlayModelSelectionPayload = ({
|
||||
agent,
|
||||
model,
|
||||
modelId,
|
||||
}: {
|
||||
agent?: ScreenCaptureAgentOption;
|
||||
model?: ScreenCaptureModelOption;
|
||||
modelId?: string;
|
||||
}) => {
|
||||
if (!shouldShowOverlayModelSelector(agent)) {
|
||||
return { modelId: undefined, provider: undefined };
|
||||
}
|
||||
|
||||
return { modelId, provider: model?.provider };
|
||||
};
|
||||
|
||||
const formatBytes = (rect: Rect): string =>
|
||||
`${Math.round(rect.width)} × ${Math.round(rect.height)} · ${OVERLAY_COPY.selectionFormatLabel}`;
|
||||
|
||||
@@ -140,6 +159,7 @@ const ChatPanel = memo<ChatPanelProps>(
|
||||
() => models?.find((item) => item.id === modelId),
|
||||
[models, modelId],
|
||||
);
|
||||
const showModelSelector = shouldShowOverlayModelSelector(currentAgent);
|
||||
|
||||
useEffect(() => {
|
||||
if (!initialAgentId) return;
|
||||
@@ -276,14 +296,29 @@ const ChatPanel = memo<ChatPanelProps>(
|
||||
|
||||
const submit = useCallback(() => {
|
||||
if (selections.length === 0 || !prompt.trim() || !allUploadsReady) return;
|
||||
const modelSelection = resolveOverlayModelSelectionPayload({
|
||||
agent: currentAgent,
|
||||
model: currentModel,
|
||||
modelId,
|
||||
});
|
||||
|
||||
onSubmit({
|
||||
agentId,
|
||||
captureIds: selections.map((item) => item.captureId),
|
||||
modelId,
|
||||
modelId: modelSelection.modelId,
|
||||
prompt: prompt.trim(),
|
||||
provider: currentModel?.provider,
|
||||
provider: modelSelection.provider,
|
||||
});
|
||||
}, [selections, prompt, agentId, modelId, currentModel, onSubmit, allUploadsReady]);
|
||||
}, [
|
||||
selections,
|
||||
prompt,
|
||||
agentId,
|
||||
currentAgent,
|
||||
modelId,
|
||||
currentModel,
|
||||
onSubmit,
|
||||
allUploadsReady,
|
||||
]);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(e: ReactKeyboardEvent<HTMLTextAreaElement>) => {
|
||||
@@ -464,38 +499,40 @@ const ChatPanel = memo<ChatPanelProps>(
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label
|
||||
aria-label={OVERLAY_COPY.modelSelectLabel}
|
||||
className={cn(styles.selectChip, !hasModels && styles.selectChipDisabled)}
|
||||
>
|
||||
{currentModel ? (
|
||||
<span className={styles.modelIconBox}>
|
||||
<ModelIcon model={currentModel.id} size={16} />
|
||||
</span>
|
||||
) : (
|
||||
<span className={styles.modelIconBoxFallback} />
|
||||
)}
|
||||
<span className={styles.chipLabel}>
|
||||
{currentModel?.displayName ??
|
||||
currentModel?.id ??
|
||||
OVERLAY_COPY.modelSelectPlaceholder}
|
||||
</span>
|
||||
<ChevronDownIcon className={styles.chevron} size={12} strokeWidth={2} />
|
||||
<select
|
||||
{showModelSelector && (
|
||||
<label
|
||||
aria-label={OVERLAY_COPY.modelSelectLabel}
|
||||
className={styles.nativeSelect}
|
||||
disabled={!hasModels}
|
||||
value={modelId ?? ''}
|
||||
onChange={handleModelChange}
|
||||
className={cn(styles.selectChip, !hasModels && styles.selectChipDisabled)}
|
||||
>
|
||||
{!hasModels && <option value="">{OVERLAY_COPY.modelSelectPlaceholder}</option>}
|
||||
{models?.map((item) => (
|
||||
<option key={item.id} value={item.id}>
|
||||
{item.displayName ?? item.id}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
{currentModel ? (
|
||||
<span className={styles.modelIconBox}>
|
||||
<ModelIcon model={currentModel.id} size={16} />
|
||||
</span>
|
||||
) : (
|
||||
<span className={styles.modelIconBoxFallback} />
|
||||
)}
|
||||
<span className={styles.chipLabel}>
|
||||
{currentModel?.displayName ??
|
||||
currentModel?.id ??
|
||||
OVERLAY_COPY.modelSelectPlaceholder}
|
||||
</span>
|
||||
<ChevronDownIcon className={styles.chevron} size={12} strokeWidth={2} />
|
||||
<select
|
||||
aria-label={OVERLAY_COPY.modelSelectLabel}
|
||||
className={styles.nativeSelect}
|
||||
disabled={!hasModels}
|
||||
value={modelId ?? ''}
|
||||
onChange={handleModelChange}
|
||||
>
|
||||
{!hasModels && <option value="">{OVERLAY_COPY.modelSelectPlaceholder}</option>}
|
||||
{models?.map((item) => (
|
||||
<option key={item.id} value={item.id}>
|
||||
{item.displayName ?? item.id}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.actionBarRight}>
|
||||
|
||||
@@ -484,8 +484,8 @@ export const connectorHidden = style({
|
||||
});
|
||||
|
||||
const fadeIn = keyframes({
|
||||
from: { opacity: 0, transform: 'translate(-50%, 8px)' },
|
||||
to: { opacity: 1, transform: 'translate(-50%, 0)' },
|
||||
from: { opacity: 0, transform: 'translateY(8px)' },
|
||||
to: { opacity: 1, transform: 'translateY(0)' },
|
||||
});
|
||||
|
||||
const spin = keyframes({
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
export const BRANDING_LOGO_URL = '';
|
||||
export const BRANDING_NAME = 'LobeHub';
|
||||
export const DEFAULT_EMBEDDING_PROVIDER = 'openai';
|
||||
export const DEFAULT_MINI_MODEL = 'gpt-5.4-mini';
|
||||
export const DEFAULT_MINI_PROVIDER = 'openai';
|
||||
export const DEFAULT_MODEL = 'claude-sonnet-4-6';
|
||||
export const DEFAULT_ONBOARDING_MODEL = 'gemini-3-flash-preview';
|
||||
export const DEFAULT_PROVIDER = 'openai';
|
||||
export const ORG_NAME = 'LobeHub';
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
[
|
||||
{
|
||||
"children": {},
|
||||
"date": "2026-05-01",
|
||||
"version": "2.1.56"
|
||||
},
|
||||
{
|
||||
"children": {},
|
||||
"date": "2026-04-29",
|
||||
|
||||
@@ -469,5 +469,6 @@
|
||||
"https://github.com/user-attachments/assets/facdc83c-e789-4649-8060-7f7a10a1b1dd": "/blog/assets05b20e40c03ced0ec8707fed2e8e0f25.webp",
|
||||
"https://github.com/user-attachments/assets/fcdfb9c5-819a-488f-b28d-0857fe861219": "/blog/assets8477415ecec1f37e38ab38ff1217d0a7.webp",
|
||||
"https://github.com/user-attachments/assets/fd60ab55-ead2-4930-ad00-fdf77662f5a0": "/blog/assets276a4e8748e9bd300b30dcd9d0e24980.webp",
|
||||
"https://file.rene.wang/clipboard-1777343750668-9b3dcb0dfff86.png": "/blog/assetsfa267a02f20bc5ba6f1273bcf27b7c9f.webp"
|
||||
"https://file.rene.wang/clipboard-1777343750668-9b3dcb0dfff86.png": "/blog/assetsfa267a02f20bc5ba6f1273bcf27b7c9f.webp",
|
||||
"https://file.rene.wang/Changelog-Seedance.png": "/blog/assetsb2bf4ddf0a45ff887a993c18cb7ab983.webp"
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
title: 'Delegate Claude Code and Codex'
|
||||
description: >-
|
||||
Delegate Claude Code and Codex from inside LobeHub, with a redesigned home, a Review tab for bulk git diffs, visual understanding, and a wave of new models.
|
||||
|
||||
|
||||
tags:
|
||||
- Coding agent
|
||||
- Claude Code
|
||||
- Home
|
||||
- Review
|
||||
- Models
|
||||
---
|
||||
|
||||
# Delegate Claude Code and Codex
|
||||
|
||||
## Features
|
||||
|
||||
- New: Delegate Claude Code and Codex in LobeHub
|
||||
- Agent-specific topic grouping: switch the topic list to group by agent, with a friendlier empty state
|
||||
- Review tab: a new tab that aggregates bulk git diffs across a tree, \~9× faster on large repos
|
||||
- Local file mention snapshots: drag a file into chat and a snapshot is captured for the model to reason over
|
||||
- Visual understanding tool: a new built-in tool for image analysis and visual reasoning
|
||||
- Line bot support: connect a Line channel as an agent endpoint
|
||||
- New models: `grok-4.3`, DeepSeek Anthropic runtime, plus `gpt-image-2` and Grok 4.20 in the model library
|
||||
|
||||
## Improvements and fixes
|
||||
|
||||
- DeepSeek now shows pricing in the model card and respects model defaults.
|
||||
- Document modal shows a skeleton while the title loads and surfaces the document update time in space.
|
||||
- Agent documents can be exposed as a virtual file system with fs-compatible output.
|
||||
- Sessions are revoked after a password reset, and tRPC pagination now enforces a max limit.
|
||||
- Skill OAuth no longer breaks the desktop app by skipping `redirectUri` on Electron.
|
||||
- CAPTCHA retries during sign-in are handled cleanly instead of failing the flow.
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: 在 LobeHub 中调度 Claude Code 与 Codex
|
||||
description: 在 LobeHub 中直接调度 Claude Code 与 Codex,全新首页、批量 git diff 的 Review 标签页、视觉理解工具,以及一批新模型。
|
||||
tags:
|
||||
- 编程 Agent
|
||||
- Claude Code
|
||||
- 首页
|
||||
- Review
|
||||
- 模型
|
||||
---
|
||||
|
||||
# 在 LobeHub 中调度 Claude Code 与 Codex
|
||||
|
||||
## 新功能
|
||||
|
||||
- 新增:在 LobeHub 中调度 Claude Code 与 Codex
|
||||
- 按 Agent 分组话题:可将话题列表切换为按 Agent 分组,并带有更友好的空状态
|
||||
- Review 标签页:新增 Review 标签页,可聚合树级别的批量 git diff,大型仓库下速度提升约 9 倍
|
||||
- 本地文件提及快照:将文件拖入聊天即可生成快照供模型理解
|
||||
- 视觉理解工具:内置的图像分析与视觉推理工具
|
||||
- Line Bot 接入:可将 Line 频道作为 Agent 接入端
|
||||
- 新模型:`grok-4.3`、DeepSeek Anthropic 运行时,以及模型库新增的 `gpt-image-2` 和 Grok 4.20
|
||||
|
||||
## 体验优化与修复
|
||||
|
||||
- DeepSeek 模型卡片展示价格并尊重模型默认配置。
|
||||
- 文档弹窗在标题加载时显示骨架,并在 Space 中展示文档更新时间。
|
||||
- Agent 文档可作为虚拟文件系统暴露,输出兼容 fs 接口。
|
||||
- 重置密码后会立即吊销已有会话,tRPC 分页接口新增最大条数限制。
|
||||
- 在桌面端跳过 Skill OAuth 的 `redirectUri`,避免应用进入异常状态。
|
||||
- 登录流程中的 CAPTCHA 重试可正常处理,不再直接失败。
|
||||
@@ -2,6 +2,15 @@
|
||||
"$schema": "https://github.com/lobehub/lobe-chat/blob/main/docs/changelog/schema.json",
|
||||
"cloud": [],
|
||||
"community": [
|
||||
{
|
||||
"image": "/blog/assetsb2bf4ddf0a45ff887a993c18cb7ab983.webp",
|
||||
"id": "2026-05-04-task-scheduler",
|
||||
"date": "2026-05-04",
|
||||
"versionRange": [
|
||||
"2.1.54",
|
||||
"2.1.56"
|
||||
]
|
||||
},
|
||||
{
|
||||
"image": "/blog/assetsfa267a02f20bc5ba6f1273bcf27b7c9f.webp",
|
||||
"id": "2026-04-27-heterogeneous-agent",
|
||||
|
||||
@@ -72,7 +72,7 @@ sequenceDiagram
|
||||
After the user sends a message, `sendMessage()`
|
||||
(`src/store/chat/slices/aiChat/actions/conversationLifecycle.ts`)
|
||||
creates the user message and assistant message placeholder,
|
||||
then calls `internal_execAgentRuntime()`.
|
||||
then calls `executeClientAgent()`.
|
||||
|
||||
### 2. Agent Runtime Drives the Loop
|
||||
|
||||
@@ -325,7 +325,7 @@ depends on the scenario:
|
||||
- **Client-side loop** (browser): Regular 1:1 chat,
|
||||
continue generation, group orchestration decisions.
|
||||
The loop runs in the browser, entry point is
|
||||
`internal_execAgentRuntime()`
|
||||
`executeClientAgent()`
|
||||
(`src/store/chat/slices/aiChat/actions/streamingExecutor.ts`)
|
||||
- **Server-side loop** (queue/local):
|
||||
Group chat supervisor agent, sub-agent tasks,
|
||||
|
||||
@@ -68,7 +68,7 @@ sequenceDiagram
|
||||
|
||||
用户发送消息后,`sendMessage()`
|
||||
(`src/store/chat/slices/aiChat/actions/conversationLifecycle.ts`)
|
||||
创建用户消息和助手消息占位,然后调用 `internal_execAgentRuntime()`。
|
||||
创建用户消息和助手消息占位,然后调用 `executeClientAgent()`。
|
||||
|
||||
### 2. Agent Runtime 驱动循环
|
||||
|
||||
@@ -293,7 +293,7 @@ Agent Runtime 循环的执行位置取决于场景:
|
||||
|
||||
- **客户端循环**(浏览器):常规 1:1 对话、继续生成、
|
||||
群组编排决策。循环在浏览器中运行,
|
||||
入口为 `internal_execAgentRuntime()`
|
||||
入口为 `executeClientAgent()`
|
||||
(`src/store/chat/slices/aiChat/actions/streamingExecutor.ts`)
|
||||
- **服务端循环**(队列 / 本地):群聊 supervisor agent、
|
||||
子 agent 任务、API/Cron 触发。循环在服务端运行,
|
||||
|
||||
@@ -1412,6 +1412,8 @@ table briefs {
|
||||
resolved_comment text
|
||||
read_at "timestamp with time zone"
|
||||
resolved_at "timestamp with time zone"
|
||||
trigger varchar(255)
|
||||
metadata jsonb
|
||||
created_at "timestamp with time zone" [not null, default: `now()`]
|
||||
|
||||
indexes {
|
||||
@@ -1422,6 +1424,7 @@ table briefs {
|
||||
type [name: 'briefs_type_idx']
|
||||
priority [name: 'briefs_priority_idx']
|
||||
(user_id, resolved_at) [name: 'briefs_unresolved_idx']
|
||||
trigger [name: 'briefs_trigger_idx']
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -196,6 +196,31 @@ SSRF_ALLOW_IP_ADDRESS_LIST=192.168.1.100,10.0.0.50
|
||||
- Default: -
|
||||
- Example: `https://cdn.example.com`
|
||||
|
||||
## Visual Understanding
|
||||
|
||||
### `VISUAL_UNDERSTANDING_PROVIDER`
|
||||
|
||||
- Type: Optional
|
||||
- Description: Provider ID of the fallback visual understanding model. Configure this together with `VISUAL_UNDERSTANDING_MODEL` to let models without native image or video understanding inspect uploaded visual media through the built-in visual understanding tool.
|
||||
- Default: -
|
||||
- Example: `openai`, `google`, or `ollama`
|
||||
|
||||
### `VISUAL_UNDERSTANDING_MODEL`
|
||||
|
||||
- Type: Optional
|
||||
- Description: Model ID used by the fallback visual understanding tool. This model should support the visual media types you want to analyze. The feature is enabled only when both `VISUAL_UNDERSTANDING_PROVIDER` and `VISUAL_UNDERSTANDING_MODEL` are configured.
|
||||
- Default: -
|
||||
- Example: `gpt-4o`, `gemini-2.5-flash`, or your local visual model ID
|
||||
|
||||
Configuration example:
|
||||
|
||||
```bash
|
||||
VISUAL_UNDERSTANDING_PROVIDER=google
|
||||
VISUAL_UNDERSTANDING_MODEL=gemini-2.5-flash
|
||||
```
|
||||
|
||||
When this feature is enabled, users can upload images or videos while using a model that does not have native visual capabilities, as long as the active model supports tool use. File upload still requires the normal file storage configuration for your deployment.
|
||||
|
||||
## AI Image
|
||||
|
||||
### `AI_IMAGE_DEFAULT_IMAGE_NUM`
|
||||
|
||||
@@ -191,6 +191,31 @@ SSRF_ALLOW_IP_ADDRESS_LIST=192.168.1.100,10.0.0.50
|
||||
- 默认值:-
|
||||
- 示例:`https://cdn.example.com`
|
||||
|
||||
## 视觉理解
|
||||
|
||||
### `VISUAL_UNDERSTANDING_PROVIDER`
|
||||
|
||||
- 类型:可选
|
||||
- 描述:兜底视觉理解模型的服务商 ID。与 `VISUAL_UNDERSTANDING_MODEL` 一起配置后,不具备原生图片或视频理解能力的模型可以通过内置视觉理解工具分析上传的视觉媒体。
|
||||
- 默认值:-
|
||||
- 示例:`openai`、`google` 或 `ollama`
|
||||
|
||||
### `VISUAL_UNDERSTANDING_MODEL`
|
||||
|
||||
- 类型:可选
|
||||
- 描述:内置视觉理解工具使用的模型 ID。该模型应支持你希望分析的视觉媒体类型。仅当 `VISUAL_UNDERSTANDING_PROVIDER` 与 `VISUAL_UNDERSTANDING_MODEL` 同时配置时,此功能才会启用。
|
||||
- 默认值:-
|
||||
- 示例:`gpt-4o`、`gemini-2.5-flash` 或你的本地视觉模型 ID
|
||||
|
||||
配置示例:
|
||||
|
||||
```bash
|
||||
VISUAL_UNDERSTANDING_PROVIDER=google
|
||||
VISUAL_UNDERSTANDING_MODEL=gemini-2.5-flash
|
||||
```
|
||||
|
||||
启用后,当当前模型没有原生视觉能力但支持工具调用时,用户仍可上传图片或视频,并由兜底视觉理解模型进行分析。文件上传本身仍需要部署中正常配置文件存储能力。
|
||||
|
||||
## AI 图像
|
||||
|
||||
### `AI_IMAGE_DEFAULT_IMAGE_NUM`
|
||||
|
||||
@@ -119,6 +119,8 @@ See [AI Provider Configuration](/docs/self-hosting/environment-variables/model-p
|
||||
- **Cloudflare R2** — No egress fees
|
||||
- **RustFS / MinIO** — Self-hosted S3 alternative (included in Docker Compose)
|
||||
|
||||
**Visual understanding fallback** — Optional, but recommended if users will upload images or videos while chatting with models that do not have native visual capabilities. Configure `VISUAL_UNDERSTANDING_PROVIDER` and `VISUAL_UNDERSTANDING_MODEL` with a visual-capable model from one of your enabled AI providers. See [Basic environment variables](/docs/self-hosting/environment-variables/basic#visual-understanding) for details.
|
||||
|
||||
**Authentication provider** — For SSO and team features (Google OAuth, GitHub OAuth, Microsoft Azure AD, Auth0, Keycloak). See [Authentication Setup](/docs/self-hosting/auth) for configuration.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
@@ -123,6 +123,8 @@ LobeHub 由以下几个关键组件组成:
|
||||
- **Cloudflare R2** — 无出口流量费用
|
||||
- **RustFS / MinIO** — 自托管 S3 替代方案(Docker Compose 已内置)
|
||||
|
||||
**视觉理解兜底模型** — 可选,但如果用户会在没有原生视觉能力的模型中上传图片或视频,建议配置。你可以使用已启用 AI 提供商中的视觉模型配置 `VISUAL_UNDERSTANDING_PROVIDER` 和 `VISUAL_UNDERSTANDING_MODEL`。详见 [基础环境变量](/zh/docs/self-hosting/environment-variables/basic#视觉理解)。
|
||||
|
||||
**认证提供商** — 支持 SSO 和团队功能(Google OAuth、GitHub OAuth、Microsoft Azure AD、Auth0、Keycloak)。配置详见 [认证设置](/docs/self-hosting/auth)。
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
"channel.userIdHint": "معرف المستخدم الخاص بك على هذه المنصة. يمكن للذكاء الاصطناعي استخدامه لإرسال رسائل مباشرة إليك.",
|
||||
"channel.userIdHint.discord": "فعّل وضع المطوّر (الإعدادات → متقدم)، ثم انقر بزر الفأرة الأيمن على صورتك الشخصية → انسخ معرّف المستخدم.",
|
||||
"channel.userIdHint.feishu": "افتح تطبيقك على منصة Feishu / Lark Open Platform → الأذونات، ثم ابحث عن المعرّف المفتوح الخاص بك.",
|
||||
"channel.userIdHint.line": "افتح وحدة تحكم مطوري LINE → قناتك → علامة تبويب الإعدادات الأساسية، ونسخ \"معرّف المستخدم الخاص بك\" (يبدأ بحرف U، 33 حرفًا).",
|
||||
"channel.userIdHint.qq": "رقم QQ الخاص بك، يظهر في صفحة ملفك الشخصي.",
|
||||
"channel.userIdHint.slack": "افتح ملفك الشخصي في Slack → ⋮ المزيد → انسخ معرّف العضو (يبدأ بـ U).",
|
||||
"channel.userIdHint.telegram": "أرسل أي رسالة إلى @userinfobot على تيليغرام — سيرد عليك بمعرّف المستخدم الرقمي الخاص بك.",
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
"authModal.signIn": "تسجيل الدخول مرة أخرى",
|
||||
"authModal.signingIn": "جارٍ تسجيل الدخول...",
|
||||
"authModal.title": "انتهت الجلسة",
|
||||
"betterAuth.captcha.continue": "استمر",
|
||||
"betterAuth.captcha.description": "أكمل التحقق الأمني أدناه. سنواصل عملية التسجيل أو تسجيل الدخول تلقائيًا.",
|
||||
"betterAuth.captcha.pendingDescription": "يرجى إكمال التحقق أولاً، ثم المتابعة.",
|
||||
"betterAuth.captcha.title": "مطلوب التحقق الأمني",
|
||||
"betterAuth.errors.confirmPasswordRequired": "يرجى تأكيد كلمة المرور",
|
||||
"betterAuth.errors.emailExists": "هذا البريد الإلكتروني مسجل بالفعل. يرجى تسجيل الدخول بدلاً من ذلك",
|
||||
"betterAuth.errors.emailInvalid": "يرجى إدخال بريد إلكتروني أو اسم مستخدم صالح",
|
||||
|
||||
+46
-2
@@ -24,6 +24,11 @@
|
||||
"agentProfile.knowledgeBases_other": "{{count}} قواعد معرفة",
|
||||
"agentProfile.skills_one": "{{count}} مهارة",
|
||||
"agentProfile.skills_other": "{{count}} مهارات",
|
||||
"agentSignal.receipts.memory.detail": "تم حفظ هذا للردود المستقبلية",
|
||||
"agentSignal.receipts.memory.title": "تم حفظ الذاكرة",
|
||||
"agentSignal.receipts.recentActivity": "النشاط الأخير",
|
||||
"agentSignal.receipts.skill.detail": "تم تحسين كيفية تعامل هذا المساعد مع الطلبات المشابهة",
|
||||
"agentSignal.receipts.skill.title": "تم تحديث المهارة",
|
||||
"agents": "الوكلاء",
|
||||
"artifact.generating": "يتم التوليد",
|
||||
"artifact.inThread": "لا يمكن العرض في الموضوع الفرعي، يرجى التبديل إلى منطقة المحادثة الرئيسية للفتح",
|
||||
@@ -317,7 +322,6 @@
|
||||
"pageSelection.reference": "النص المحدد",
|
||||
"pin": "تثبيت",
|
||||
"pinOff": "إلغاء التثبيت",
|
||||
"prompts.summaryExpert": "بصفتك خبيرًا في التلخيص، يرجى تلخيص المحتوى التالي بناءً على التعليمات أعلاه:",
|
||||
"rag.referenceChunks": "مصدر المرجع",
|
||||
"rag.userQuery.actions.delete": "حذف إعادة صياغة الاستعلام",
|
||||
"rag.userQuery.actions.regenerate": "إعادة توليد الاستعلام",
|
||||
@@ -490,6 +494,7 @@
|
||||
"taskDetail.comment.edit": "تعديل",
|
||||
"taskDetail.comment.save": "حفظ",
|
||||
"taskDetail.commentPlaceholder": "اترك تعليقًا...",
|
||||
"taskDetail.commentSubmitAndRun": "إرسال وتشغيل الآن",
|
||||
"taskDetail.deleteConfirm.content": "لا يمكن التراجع عن هذا الإجراء.",
|
||||
"taskDetail.deleteConfirm.ok": "حذف",
|
||||
"taskDetail.deleteConfirm.title": "هل تريد حذف هذه المهمة؟",
|
||||
@@ -514,6 +519,23 @@
|
||||
"taskDetail.properties": "الخصائص",
|
||||
"taskDetail.reassignDisabled": "لا يمكن إعادة إسناد الوكيل أثناء تشغيل المهمة",
|
||||
"taskDetail.rerunTask": "إعادة تشغيل المهمة",
|
||||
"taskDetail.runAll": "تشغيل الكل",
|
||||
"taskDetail.runAll.cancel": "إلغاء",
|
||||
"taskDetail.runAll.confirm": "تشغيل {{count}} مهمة فرعية",
|
||||
"taskDetail.runAll.cycleWarning": "تم اكتشاف اعتماد دائري. المهام المتورطة أو المحظورة بسبب الدورة لن يتم تشغيلها: {{members}}",
|
||||
"taskDetail.runAll.description": "سيتم تشغيل المهام الفرعية طبقة بطبقة. كل طبقة تنتظر انتهاء الطبقة السابقة. المهام التي ليس لها تبعيات تعمل في الطبقة الأولى.",
|
||||
"taskDetail.runAll.empty": "لا يوجد شيء للتشغيل — كل مهمة فرعية مكتملة بالفعل، قيد التنفيذ، أو عالقة في دورة.",
|
||||
"taskDetail.runAll.kickedOff": "تم بدء {{count}} مهمة فرعية؛ ستتبع الطبقات اللاحقة.",
|
||||
"taskDetail.runAll.layer": "الطبقة {{index}}",
|
||||
"taskDetail.runAll.layerHint.first": "تبدأ فورًا",
|
||||
"taskDetail.runAll.layerHint.next": "تنتظر انتهاء الطبقة {{prev}}",
|
||||
"taskDetail.runAll.loading": "جارٍ تحميل خطة المهام الفرعية...",
|
||||
"taskDetail.runAll.partialFailure": "تم بدء {{ok}} من {{total}} مهمة فرعية؛ فشلت {{failed}}.",
|
||||
"taskDetail.runAll.skipped.alreadyDone": "{{count}} مهمة مكتملة أو ملغاة بالفعل — تم تخطيها",
|
||||
"taskDetail.runAll.skipped.blockedExternally": "{{count}} مهمة تنتظر عائقًا خارج هذه المجموعة — ستعمل تلقائيًا عند إزالة العائق",
|
||||
"taskDetail.runAll.skipped.ineligible": "{{count}} مهمة قيد التشغيل أو مجدولة — تم تخطيها",
|
||||
"taskDetail.runAll.title": "تشغيل المهام الفرعية بترتيب التبعيات",
|
||||
"taskDetail.runNow": "تشغيل الآن",
|
||||
"taskDetail.runTask": "تشغيل المهمة",
|
||||
"taskDetail.saveModelConfig": "حفظ",
|
||||
"taskDetail.status.backlog": "قائمة الانتظار",
|
||||
@@ -599,6 +621,7 @@
|
||||
"taskSchedule.scheduleType.weekly": "أسبوعي",
|
||||
"taskSchedule.scheduler": "الجدولة",
|
||||
"taskSchedule.schedulerTab": "الجدولة",
|
||||
"taskSchedule.startScheduling": "ابدأ الجدولة",
|
||||
"taskSchedule.summary.daily": "يوميًا عند {{time}}",
|
||||
"taskSchedule.summary.disabled": "الأتمتة متوقفة",
|
||||
"taskSchedule.summary.everyNHours": "كل {{count}} ساعات{{minute}}",
|
||||
@@ -762,7 +785,6 @@
|
||||
"workflow.toolDisplayName.finishOnboarding": "إنهاء الإعداد التعريفي",
|
||||
"workflow.toolDisplayName.getCommandOutput": "قراءة مخرجات الأمر",
|
||||
"workflow.toolDisplayName.getDocument": "قراءة مستند",
|
||||
"workflow.toolDisplayName.getOnboardingState": "تم التحقق من حالة الإعداد الأولي",
|
||||
"workflow.toolDisplayName.getPageContent": "قراءة محتوى الصفحة",
|
||||
"workflow.toolDisplayName.getTopicContext": "قراءة سياق الموضوع",
|
||||
"workflow.toolDisplayName.globLocalFiles": "الملفات التي تم البحث فيها",
|
||||
@@ -786,6 +808,7 @@
|
||||
"workflow.toolDisplayName.replaceDocumentContent": "تم استبدال محتوى المستند",
|
||||
"workflow.toolDisplayName.replaceText": "تم استبدال النص",
|
||||
"workflow.toolDisplayName.runCommand": "تم تنفيذ أمر",
|
||||
"workflow.toolDisplayName.saveUserQuestion": "تم تسجيل المعلومات",
|
||||
"workflow.toolDisplayName.search": "تم البحث في الويب",
|
||||
"workflow.toolDisplayName.searchAgent": "الوكلاء الذين تم البحث عنهم",
|
||||
"workflow.toolDisplayName.searchKnowledgeBase": "تم البحث في قاعدة المعرفة",
|
||||
@@ -799,6 +822,7 @@
|
||||
"workflow.toolDisplayName.updateLoadRule": "تم تحديث قاعدة التحميل",
|
||||
"workflow.toolDisplayName.updatePlan": "الخطة المحدَّثة",
|
||||
"workflow.toolDisplayName.updateTodos": "تم تحديث المهام",
|
||||
"workflow.toolDisplayName.writeDocument": "تم كتابة مستند",
|
||||
"workflow.toolDisplayName.writeLocalFile": "تمت كتابة ملف",
|
||||
"workflow.working": "جارٍ العمل...",
|
||||
"workingPanel.agentDocuments": "Agent Documents",
|
||||
@@ -830,8 +854,28 @@
|
||||
"workingPanel.resources.renameEmpty": "Title cannot be empty",
|
||||
"workingPanel.resources.renameError": "Failed to rename document",
|
||||
"workingPanel.resources.renameSuccess": "Document renamed",
|
||||
"workingPanel.resources.updatedAt": "تم التحديث في {{time}}",
|
||||
"workingPanel.resources.viewMode.list": "عرض القائمة",
|
||||
"workingPanel.resources.viewMode.tree": "عرض الشجرة",
|
||||
"workingPanel.review.binary": "ملف ثنائي — لا يمكن عرض الفرق",
|
||||
"workingPanel.review.collapseAll": "طي الكل",
|
||||
"workingPanel.review.copied": "تم نسخ المسار",
|
||||
"workingPanel.review.copyPath": "نسخ مسار الملف",
|
||||
"workingPanel.review.empty": "لا توجد تغييرات في شجرة العمل",
|
||||
"workingPanel.review.error": "تعذر تحميل الفرق لهذا الملف",
|
||||
"workingPanel.review.expandAll": "توسيع الكل",
|
||||
"workingPanel.review.more": "خيارات إضافية",
|
||||
"workingPanel.review.refresh": "تحديث",
|
||||
"workingPanel.review.textDiff.disable": "تعطيل مقارنة النصوص المضمنة",
|
||||
"workingPanel.review.textDiff.enable": "تمكين مقارنة النصوص المضمنة",
|
||||
"workingPanel.review.title": "مراجعة",
|
||||
"workingPanel.review.tooLarge": "الملف كبير جدًا لعرض الفرق داخليًا",
|
||||
"workingPanel.review.unstaged": "غير مُعدّل",
|
||||
"workingPanel.review.viewMode.split": "التبديل إلى العرض المنقسم",
|
||||
"workingPanel.review.viewMode.unified": "التبديل إلى العرض الموحد",
|
||||
"workingPanel.review.wordWrap.disable": "تعطيل التفاف النص",
|
||||
"workingPanel.review.wordWrap.enable": "تمكين التفاف النص",
|
||||
"workingPanel.space": "مسافة",
|
||||
"workingPanel.title": "Working Panel",
|
||||
"you": "أنت",
|
||||
"zenMode": "وضع التركيز"
|
||||
|
||||
@@ -448,6 +448,10 @@
|
||||
"telemetry.title": "ساعدنا في تحسين {{appName}}",
|
||||
"temp": "مؤقت",
|
||||
"terms": "شروط الخدمة",
|
||||
"time.formatOtherYear": "MMM D، YYYY",
|
||||
"time.formatThisYear": "MMM D",
|
||||
"time.today": "اليوم",
|
||||
"time.yesterday": "أمس",
|
||||
"unknownError": "خطأ غير معروف",
|
||||
"update": "تحديث",
|
||||
"updateAgent": "تحديث معلومات الوكيل",
|
||||
|
||||
@@ -141,6 +141,7 @@
|
||||
"ModelSwitchPanel.detail.pricing.unit.textInput_cacheWrite": "مدخل (كتابة في التخزين)",
|
||||
"ModelSwitchPanel.detail.pricing.unit.textOutput": "مخرج",
|
||||
"ModelSwitchPanel.detail.pricing.unit.videoGeneration": "إنشاء الفيديو",
|
||||
"ModelSwitchPanel.detail.pricing.unit.videoInput": "مدخل الفيديو",
|
||||
"ModelSwitchPanel.detail.releasedAt": "تم الإصدار في {{date}}",
|
||||
"ModelSwitchPanel.emptyModel": "لا يوجد نموذج مفعل. يرجى الذهاب إلى الإعدادات لتفعيله.",
|
||||
"ModelSwitchPanel.emptyProvider": "لا يوجد مزود مفعل. يرجى الذهاب إلى الإعدادات لتفعيل أحدهم.",
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"agentSelection.search": "لم يتم العثور على وكلاء مطابقين",
|
||||
"brief.action.acknowledge": "إقرار",
|
||||
"brief.action.approve": "الموافقة",
|
||||
"brief.action.confirmDone": "تأكيد الإنهاء",
|
||||
"brief.action.confirm": "تأكيد",
|
||||
"brief.action.confirmDone": "تأكيد",
|
||||
"brief.action.feedback": "ملاحظات",
|
||||
"brief.action.retry": "إعادة المحاولة",
|
||||
"brief.addFeedback": "مشاركة الملاحظات",
|
||||
@@ -22,6 +23,7 @@
|
||||
"brief.resolved": "تم وضع علامة كمُعالَج",
|
||||
"brief.title": "الموجز اليومي",
|
||||
"brief.viewAllTasks": "عرض جميع المهام",
|
||||
"brief.viewRun": "عرض التشغيل",
|
||||
"project.create": "مشروع جديد",
|
||||
"project.deleteConfirm": "سيتم حذف هذا المشروع ولن يمكن استعادته. أكد للمتابعة.",
|
||||
"starter.createAgent": "إنشاء وكيل",
|
||||
|
||||
+43
-85
@@ -84,7 +84,6 @@
|
||||
"Kimi-K2.5.description": "Kimi K2.5 هو أقوى نموذج من سلسلة Kimi، ويقدم أداءً متقدماً مفتوح المصدر في مهام الوكلاء والبرمجة وفهم الرؤية. يدعم الإدخال متعدد الوسائط ووضعَي التفكير وغير التفكير.",
|
||||
"Kolors.description": "Kolors هو نموذج تحويل نص إلى صورة طوره فريق Kolors في Kuaishou. مدرب على مليارات المعاملات، يتميز بجودة بصرية عالية، فهم دلالي قوي للغة الصينية، وقدرات متميزة في عرض النصوص.",
|
||||
"Kwai-Kolors/Kolors.description": "Kolors هو نموذج تحويل نص إلى صورة واسع النطاق من فريق Kolors في Kuaishou. مدرب على مليارات أزواج النصوص والصور، يتفوق في الجودة البصرية، الدقة الدلالية المعقدة، وعرض النصوص الصينية/الإنجليزية، مع فهم وتوليد قويين للمحتوى الصيني.",
|
||||
"Kwaipilot/KAT-Dev.description": "KAT-Dev (32B) هو نموذج مفتوح المصدر لمهام هندسة البرمجيات. يحقق معدل حل 62.4% على SWE-Bench Verified، ويحتل المرتبة الخامسة بين النماذج المفتوحة. تم تحسينه عبر التدريب الوسيط، SFT، وRL لإكمال الشيفرة، إصلاح الأخطاء، ومراجعة الشيفرة.",
|
||||
"Llama-3.2-11B-Vision-Instruct.description": "استدلال بصري قوي على الصور عالية الدقة، مناسب لتطبيقات الفهم البصري.",
|
||||
"Llama-3.2-90B-Vision-Instruct\t.description": "استدلال بصري متقدم لتطبيقات الفهم البصري المعتمدة على الوكلاء.",
|
||||
"LongCat-2.0-Preview.description": "الميزات الأساسية لـ LongCat-2.0-Preview هي كما يلي: مصمم لسيناريوهات تطوير الوكلاء، مع دعم أصلي لاستخدام الأدوات، التفكير متعدد الخطوات، ومهام السياق الطويل؛ يتفوق في توليد الأكواد، سير العمل الآلي، وتنفيذ التعليمات المعقدة؛ متكامل بعمق مع أدوات الإنتاجية مثل Claude Code، OpenClaw، OpenCode، وKilo Code.",
|
||||
@@ -107,6 +106,7 @@
|
||||
"MiniMax-Hailuo-2.3.description": "نموذج جديد لإنشاء الفيديو مع تحسينات شاملة في حركة الجسم، والواقعية الفيزيائية، واتباع التعليمات.",
|
||||
"MiniMax-M1.description": "نموذج استدلال داخلي جديد بسلسلة تفكير تصل إلى 80K ومدخلات حتى 1M، يقدم أداءً مماثلاً لأفضل النماذج العالمية.",
|
||||
"MiniMax-M2-Stable.description": "مصمم لتدفقات العمل البرمجية والوكلاء بكفاءة عالية، مع قدرة تزامن أعلى للاستخدام التجاري.",
|
||||
"MiniMax-M2.1-Lightning.description": "قدرات برمجة متعددة اللغات قوية مع استنتاج أسرع وأكثر كفاءة.",
|
||||
"MiniMax-M2.1-highspeed.description": "قدرات برمجة متعددة اللغات قوية، تجربة برمجة مطورة بشكل شامل. أسرع وأكثر كفاءة.",
|
||||
"MiniMax-M2.1.description": "MiniMax-M2.1 هو نموذج مفتوح المصدر رائد من MiniMax، يركز على حل المهام الواقعية المعقدة. يتميز بقدرات برمجة متعددة اللغات والقدرة على أداء المهام المعقدة كوكلاء ذكي.",
|
||||
"MiniMax-M2.5-highspeed.description": "MiniMax M2.5 Highspeed: نفس أداء M2.5 مع استدلال أسرع.",
|
||||
@@ -116,6 +116,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 مليار نشطة لكل رمز. يدعم سياق 1 مليون بشكل طبيعي ويستخدم Flash Attention لتقليل FLOPs بنسبة 75% على توليد 100 ألف رمز مقارنة بـ DeepSeek R1. مع بنية MoE بالإضافة إلى CISPO وتدريب RL الهجين، يحقق أداءً رائدًا في الاستدلال طويل المدخلات ومهام الهندسة البرمجية الواقعية.",
|
||||
"MiniMaxAI/MiniMax-M2.5.description": "MiniMax-M2.5 هو أحدث نموذج لغة كبير تم تطويره بواسطة MiniMax، تم تدريبه من خلال التعلم المعزز واسع النطاق عبر مئات الآلاف من البيئات المعقدة الواقعية. يتميز بهيكل MoE مع 229 مليار معلمة، ويحقق أداءً رائدًا في الصناعة في مهام مثل البرمجة، استدعاء أدوات الوكلاء، البحث، وسيناريوهات المكتب.",
|
||||
"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) هو نموذج تعليمات عالي الدقة للحسابات المعقدة.",
|
||||
@@ -132,7 +133,6 @@
|
||||
"Pro/MiniMaxAI/MiniMax-M2.5.description": "MiniMax-M2.5 هو أحدث نموذج لغة كبير تم تطويره بواسطة MiniMax، تم تدريبه من خلال التعلم المعزز واسع النطاق عبر مئات الآلاف من البيئات الواقعية المعقدة. يتميز ببنية MoE مع 229 مليار معلمة، ويحقق أداءً رائدًا في الصناعة في مهام مثل البرمجة، استدعاء أدوات الوكلاء، البحث، وسيناريوهات المكتب.",
|
||||
"Pro/Qwen/Qwen2.5-7B-Instruct.description": "Qwen2.5-7B-Instruct هو جزء من أحدث سلسلة نماذج لغوية كبيرة من Alibaba Cloud. يقدم هذا النموذج ذو 7 مليارات معلمة تحسينات ملحوظة في البرمجة والرياضيات، ويدعم أكثر من 29 لغة، ويعزز اتباع التعليمات، وفهم البيانات المنظمة، وإنتاج المخرجات المنظمة (خصوصًا JSON).",
|
||||
"Pro/THUDM/GLM-4.1V-9B-Thinking.description": "GLM-4.1V-9B-Thinking هو نموذج رؤية-لغة مفتوح المصدر من Zhipu AI ومختبر KEG في جامعة تسينغهوا، مصمم للإدراك متعدد الوسائط المعقد. مبني على GLM-4-9B-0414، ويضيف استدلال سلسلة الأفكار والتعلم المعزز (RL) لتحسين الاستدلال عبر الوسائط والاستقرار بشكل كبير.",
|
||||
"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.",
|
||||
@@ -140,18 +140,18 @@
|
||||
"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/moonshotai/Kimi-K2.6.description": "Kimi K2.6 هو نموذج وكيل متعدد الوسائط مفتوح المصدر من Moonshot AI، يحقق أداءً رائدًا مفتوح المصدر على العديد من المعايير الرئيسية بما في ذلك HLE (مع الأدوات)، SWE-Bench Pro، وBrowseComp. يعتمد النموذج على هيكل MoE مع إجمالي 1T معلمات و32B معلمات نشطة، يدعم نافذة سياق 256K رمز، ويجمع بين قدرات متعددة الوسائط الأصلية.",
|
||||
"Pro/zai-org/GLM-5.1.description": "GLM-5.1 هو نموذج الجيل التالي الرائد المصمم لهندسة الوكلاء، ويستخدم بنية خبراء مختلطة (MoE) بـ 754 مليار معلمة. يعزز قدرات البرمجة بشكل كبير، محققاً نتائج متقدمة على SWE-Bench Pro، ويتفوق بوضوح على سابقه في مقاييس مثل NL2Repo وTerminal-Bench 2.0. مصمم لمهام الوكلاء طويلة الأمد، ويتعامل مع الأسئلة الغامضة بشكل أدق، ويحلل المهام المعقدة، وينفذ التجارب، ويفحص النتائج، ويواصل التحسين عبر مئات الدورات وآلاف استدعاءات الأدوات.",
|
||||
"Pro/zai-org/glm-4.7.description": "GLM-4.7 هو النموذج الرائد الجديد من Zhipu مع 355 مليار معلمة إجمالية و32 مليار معلمة نشطة، تم ترقيته بالكامل في الحوار العام، المنطق، وقدرات الوكلاء. يعزز GLM-4.7 التفكير المتداخل ويقدم التفكير المحفوظ والتفكير على مستوى الدور.",
|
||||
"Pro/zai-org/glm-5.1.description": "GLM-5.1 هو نموذج وكيل رائد من الجيل التالي من Zhipu للهندسة الذكية. يستخدم هيكل Mixture-of-Experts مع 754 مليار معلمة، مع استدعاء أدوات أصلية، إكمال بادئة، دعم FIM، ونافذة سياق 200K لتدفقات العمل طويلة الأمد.",
|
||||
"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/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 للتحكم في المظهر، مما يتيح تحريرًا على مستوى الدلالة والمظهر. يدعم التعديلات المحلية (إضافة/إزالة/تعديل) والتعديلات الدلالية المتقدمة مثل إنشاء الملكية الفكرية ونقل الأسلوب مع الحفاظ على المعنى. يحقق نتائج رائدة في العديد من المعايير.",
|
||||
"Qwen/Qwen-Image.description": "Qwen-Image هو نموذج أساسي لتوليد الصور يحتوي على 20 مليار معلمة من فريق Qwen. يحقق تقدمًا كبيرًا في عرض النصوص المعقدة وتحرير الصور بدقة، خاصة للنصوص الصينية/الإنجليزية عالية الدقة. يدعم تخطيطات متعددة الأسطر والفقرة مع الحفاظ على تناسق الطباعة. بالإضافة إلى عرض النصوص، يدعم مجموعة واسعة من الأساليب من الواقعية إلى الأنمي، والتحرير المتقدم مثل نقل الأسلوب، إضافة/إزالة الكائنات، تحسين التفاصيل، تحرير النصوص، والتحكم في الوضعية، ويهدف إلى أن يكون نموذجًا أساسيًا شاملاً للإبداع البصري.",
|
||||
"Qwen/Qwen2-72B-Instruct.description": "يقدم Qwen 2 Instruct (72B) استجابة دقيقة للتعليمات، مما يجعله مناسبًا لأعباء العمل المؤسسية.",
|
||||
"Qwen/Qwen2-7B-Instruct.description": "Qwen2-7B-Instruct هو نموذج بحجم 7B مضبوط على التعليمات ضمن سلسلة Qwen2، يستخدم تقنيات Transformer وSwiGLU وQKV bias والانتباه المجمع. يتميز بقدرته على معالجة مدخلات كبيرة وأداء قوي في مجالات الفهم، التوليد، التعدد اللغوي، البرمجة، الرياضيات، والاستدلال، متفوقًا على معظم النماذج المفتوحة وسابقه Qwen1.5-7B-Chat في عدة تقييمات.",
|
||||
"Qwen/Qwen2-VL-72B-Instruct.description": "Qwen2-VL هو أحدث نموذج من سلسلة Qwen-VL، يحقق نتائج رائدة في اختبارات الرؤية مثل MathVista وDocVQA وRealWorldQA وMTVQA. يمكنه فهم مقاطع فيديو تتجاوز 20 دقيقة لأغراض الأسئلة والأجوبة، الحوار، وإنشاء المحتوى. كما يدعم الاستدلال المعقد واتخاذ القرار، ويتكامل مع الأجهزة/الروبوتات لتنفيذ إجراءات تعتمد على الرؤية. بالإضافة إلى الإنجليزية والصينية، يمكنه قراءة نصوص بلغات متعددة تشمل معظم اللغات الأوروبية، اليابانية، الكورية، العربية، والفيتنامية.",
|
||||
"Qwen/Qwen2.5-14B-Instruct.description": "Qwen2.5-14B-Instruct هو جزء من أحدث سلسلة نماذج LLM من Alibaba Cloud. يوفر هذا النموذج بحجم 14B تحسينات ملحوظة في البرمجة والرياضيات، ويدعم أكثر من 29 لغة، ويعزز اتباع التعليمات وفهم البيانات المنظمة وإنتاج مخرجات منظمة (خصوصًا بصيغة JSON).",
|
||||
"Qwen/Qwen2.5-32B-Instruct.description": "Qwen2.5-32B-Instruct هو جزء من أحدث سلسلة نماذج LLM من Alibaba Cloud. يوفر هذا النموذج بحجم 32B تحسينات ملحوظة في البرمجة والرياضيات، ويدعم أكثر من 29 لغة، ويعزز اتباع التعليمات وفهم البيانات المنظمة وإنتاج مخرجات منظمة (خصوصًا بصيغة JSON).",
|
||||
"Qwen/Qwen2.5-72B-Instruct-128K.description": "Qwen2.5-72B-Instruct هو جزء من أحدث سلسلة نماذج LLM من Alibaba Cloud. يوفر هذا النموذج بحجم 72B تحسينات في البرمجة والرياضيات، ويدعم مدخلات تصل إلى 128K ومخرجات تتجاوز 8K، ويشمل دعمًا لأكثر من 29 لغة، مع تحسينات في اتباع التعليمات وإنتاج مخرجات منظمة (خصوصًا بصيغة JSON).",
|
||||
@@ -160,23 +160,17 @@
|
||||
"Qwen/Qwen2.5-7B-Instruct-Turbo.description": "Qwen2.5 هو عائلة جديدة من نماذج LLM مصممة خصيصًا لمهام تعتمد على التعليمات.",
|
||||
"Qwen/Qwen2.5-7B-Instruct.description": "Qwen2.5-7B-Instruct هو جزء من أحدث سلسلة نماذج LLM من Alibaba Cloud. يوفر هذا النموذج بحجم 7B تحسينات ملحوظة في البرمجة والرياضيات، ويدعم أكثر من 29 لغة، ويعزز اتباع التعليمات وفهم البيانات المنظمة وإنتاج مخرجات منظمة (خصوصًا بصيغة JSON).",
|
||||
"Qwen/Qwen2.5-Coder-32B-Instruct.description": "Qwen2.5 Coder 32B Instruct هو أحدث نموذج LLM من Alibaba Cloud يركز على البرمجة. مبني على Qwen2.5 ومدرب على 5.5 تريليون رمز، يعزز بشكل كبير توليد الشيفرة، الاستدلال، وتصحيح الأخطاء، مع الحفاظ على قدرات قوية في الرياضيات والمهام العامة، مما يجعله أساسًا قويًا لوكلاء البرمجة.",
|
||||
"Qwen/Qwen2.5-VL-32B-Instruct.description": "Qwen2.5-VL-32B-Instruct هو نموذج متعدد الوسائط من فريق Qwen. يتعرف على الكائنات الشائعة ويحلل النصوص، الرسوم البيانية، الأيقونات، الرسومات، والتصاميم. كوكل بصري، يمكنه الاستدلال والتحكم الديناميكي في الأدوات، بما في ذلك استخدام الحاسوب والهاتف. يحدد الكائنات بدقة وينتج مخرجات منظمة للفواتير والجداول. مقارنة بـ Qwen2-VL، يوفر تحسينات إضافية في الرياضيات وحل المشكلات، مع استجابات مفضلة أكثر من قبل البشر.",
|
||||
"Qwen/Qwen2.5-VL-72B-Instruct.description": "Qwen2.5-VL هو نموذج رؤية-لغة في سلسلة Qwen2.5 مع ترقيات رئيسية: فهم بصري أقوى للكائنات، النصوص، الرسوم البيانية، والتصاميم؛ الاستدلال كوكل بصري باستخدام أدوات ديناميكية؛ فهم مقاطع فيديو تتجاوز الساعة والتقاط الأحداث الرئيسية؛ تحديد دقيق للكائنات باستخدام مربعات أو نقاط؛ ومخرجات منظمة للبيانات الممسوحة مثل الفواتير والجداول.",
|
||||
"Qwen/Qwen3-14B.description": "Qwen3 هو الجيل التالي من نموذج Tongyi Qwen، يحقق تقدمًا كبيرًا في الاستدلال، القدرات العامة، قدرات الوكلاء، والأداء متعدد اللغات، ويدعم التبديل بين أوضاع التفكير.",
|
||||
"Qwen/Qwen3-235B-A22B-Instruct-2507.description": "Qwen3-235B-A22B-Instruct-2507 هو النموذج الرائد من نوع MoE في سلسلة Qwen3، يحتوي على 235 مليار معلمة إجمالية و22 مليار نشطة. هو إصدار غير مفكر محدث يركز على تحسين اتباع التعليمات، الاستدلال المنطقي، فهم النصوص، الرياضيات، العلوم، البرمجة، واستخدام الأدوات. كما يوسع المعرفة متعددة اللغات ويعزز التوافق مع تفضيلات المستخدم في المهام المفتوحة الذاتية.",
|
||||
"Qwen/Qwen3-235B-A22B-Thinking-2507.description": "Qwen3-235B-A22B-Thinking-2507 هو نموذج Qwen3 مخصص للاستدلال المعقد. يستخدم بنية MoE مع 235 مليار معلمة إجمالية وحوالي 22 مليار نشطة لكل رمز لتعزيز الكفاءة. كنموذج تفكير مخصص، يظهر تقدمًا كبيرًا في المنطق، الرياضيات، العلوم، البرمجة، والمعايير الأكاديمية، محققًا أداءً رائدًا في التفكير المفتوح. كما يحسن اتباع التعليمات، استخدام الأدوات، وتوليد النصوص، ويدعم سياقًا يصل إلى 256K للاستدلال العميق والوثائق الطويلة.",
|
||||
"Qwen/Qwen3-235B-A22B.description": "Qwen3 235B A22B هو نموذج Qwen3 واسع النطاق يقدم قدرات ذكاء اصطناعي من الدرجة الأولى.",
|
||||
"Qwen/Qwen3-30B-A3B-Instruct-2507.description": "Qwen3-30B-A3B-Instruct-2507 هو الإصدار غير المفكر المحدث من Qwen3-30B-A3B. هو نموذج MoE يحتوي على 30.5 مليار معلمة إجمالية و3.3 مليار نشطة. يعزز بشكل كبير اتباع التعليمات، الاستدلال المنطقي، فهم النصوص، الرياضيات، العلوم، البرمجة، واستخدام الأدوات، ويوسع المعرفة متعددة اللغات، ويتماشى بشكل أفضل مع تفضيلات المستخدم في المهام المفتوحة الذاتية. يدعم سياقًا يصل إلى 256K. هذا النموذج غير مفكر فقط ولن ينتج علامات `<think></think>`.",
|
||||
"Qwen/Qwen3-30B-A3B-Instruct-2507.description": "Qwen3-30B-A3B-Instruct-2507 هو الإصدار المحدث غير المفكر من Qwen3-30B-A3B. إنه نموذج MoE مع إجمالي 30.5 مليار و3.3 مليار معلمات نشطة. يحسن بشكل كبير اتباع التعليمات، التفكير المنطقي، فهم النصوص، الرياضيات، العلوم، البرمجة، واستخدام الأدوات، ويوسع المعرفة متعددة اللغات طويلة الذيل، ويتماشى بشكل أفضل مع تفضيلات المستخدم في المهام المفتوحة الذاتية. يدعم سياق 256K. هذا النموذج غير مفكر فقط ولن يخرج علامات `נקוד`.",
|
||||
"Qwen/Qwen3-30B-A3B-Thinking-2507.description": "Qwen3-30B-A3B-Thinking-2507 هو أحدث نموذج تفكير في سلسلة Qwen3. هو نموذج MoE يحتوي على 30.5 مليار معلمة إجمالية و3.3 مليار نشطة، يركز على المهام المعقدة. يظهر تقدمًا كبيرًا في المنطق، الرياضيات، العلوم، البرمجة، والمعايير الأكاديمية، ويحسن اتباع التعليمات، استخدام الأدوات، توليد النصوص، والتوافق مع التفضيلات. يدعم سياقًا يصل إلى 256K ويمكن توسيعه إلى مليون رمز. هذا الإصدار مصمم لوضع التفكير مع استدلال تفصيلي خطوة بخطوة وقدرات وكيل قوية.",
|
||||
"Qwen/Qwen3-32B.description": "Qwen3 هو الجيل التالي من نموذج Tongyi Qwen، يحقق تقدمًا كبيرًا في الاستدلال، القدرات العامة، قدرات الوكلاء، والأداء متعدد اللغات، ويدعم التبديل بين أوضاع التفكير.",
|
||||
"Qwen/Qwen3-8B.description": "Qwen3 هو الجيل التالي من نموذج Tongyi Qwen، يحقق تقدمًا كبيرًا في الاستدلال، القدرات العامة، قدرات الوكلاء، والأداء متعدد اللغات، ويدعم التبديل بين أوضاع التفكير.",
|
||||
"Qwen/Qwen3-Coder-30B-A3B-Instruct.description": "Qwen3-Coder-30B-A3B-Instruct هو نموذج برمجة من سلسلة Qwen3. مصمم لتحقيق أداء وكفاءة عالية مع تعزيز قدرات البرمجة. يظهر تفوقًا في البرمجة الوكيلة، تشغيل المتصفح التلقائي، واستخدام الأدوات بين النماذج المفتوحة. يدعم سياقًا يصل إلى 256K ويمكن توسيعه إلى مليون رمز لفهم على مستوى قواعد الشيفرة. يدعم البرمجة الوكيلة على منصات مثل Qwen Code وCLINE باستخدام تنسيق مخصص لاستدعاء الوظائف.",
|
||||
"Qwen/Qwen3-Coder-480B-A35B-Instruct.description": "Qwen3-Coder-480B-A35B-Instruct هو أقوى نموذج برمجة من Alibaba حتى الآن. يعتمد على بنية MoE ويحتوي على 480 مليار معلمة إجمالية و35 مليار معلمة نشطة، مما يوازن بين الكفاءة والأداء. يدعم سياقًا يصل إلى 256 ألف رمز بشكل أصلي، ويمكن توسيعه إلى مليون رمز باستخدام YaRN، مما يتيح التعامل مع قواعد بيانات برمجية ضخمة. صُمم لسير عمل برمجي قائم على الوكلاء، ويمكنه التفاعل مع الأدوات والبيئات لحل مهام برمجية معقدة. يحقق نتائج رائدة بين النماذج المفتوحة في اختبارات البرمجة والوكلاء، ويقارن بأداء نماذج مثل Claude Sonnet 4.",
|
||||
"Qwen/Qwen3-Omni-30B-A3B-Captioner.description": "Qwen3-Omni-30B-A3B-Captioner هو نموذج رؤية-لغة من سلسلة Qwen3 مصمم لتوليد أوصاف صور عالية الجودة، دقيقة ومفصلة. يستخدم بنية MoE تحتوي على 30 مليار معلمة لفهم الصور بعمق وتوليد أوصاف سلسة، ويتفوق في التقاط التفاصيل، وفهم المشاهد، والتعرف على الكائنات، والاستدلال العلاقي.",
|
||||
"Qwen/Qwen3-Omni-30B-A3B-Instruct.description": "Qwen3-Omni-30B-A3B-Instruct هو نموذج MoE من سلسلة Qwen3 يحتوي على 30 مليار معلمة إجمالية و3 مليارات نشطة، ويقدم أداءً قويًا بتكلفة تنفيذ منخفضة. تم تدريبه على بيانات متعددة اللغات وعالية الجودة من مصادر متنوعة، ويدعم إدخالًا متعدد الوسائط (نص، صور، صوت، فيديو) وفهمًا وتوليدًا عبر الوسائط.",
|
||||
"Qwen/Qwen3-Omni-30B-A3B-Thinking.description": "Qwen3-Omni-30B-A3B-Thinking هو المكون الأساسي \"المفكر\" في Qwen3-Omni. يعالج مدخلات متعددة الوسائط (نص، صوت، صور، فيديو) ويؤدي استدلالًا معقدًا بتسلسل تفكير، موحدًا المدخلات في تمثيل مشترك لفهم عميق عبر الوسائط. إنه نموذج MoE يحتوي على 30 مليار معلمة إجمالية و3 مليارات نشطة، ويوازن بين قوة الاستدلال وكفاءة الحوسبة.",
|
||||
"Qwen/Qwen3-VL-235B-A22B-Instruct.description": "Qwen3-VL-235B-A22B-Instruct هو نموذج Qwen3-VL كبير موجه للتعليمات، مبني على بنية MoE، ويقدم فهمًا وتوليدًا متعدد الوسائط ممتازًا. يدعم سياقًا يصل إلى 256 ألف رمز بشكل أصلي، ومناسب لخدمات الإنتاج متعددة الوسائط ذات التوافر العالي.",
|
||||
"Qwen/Qwen3-VL-235B-A22B-Thinking.description": "Qwen3-VL-235B-A22B-Thinking هو الإصدار الرائد للتفكير من Qwen3-VL، مُحسَّن للاستدلال متعدد الوسائط المعقد، والاستدلال في السياقات الطويلة، وتفاعل الوكلاء في سيناريوهات المؤسسات.",
|
||||
"Qwen/Qwen3-VL-30B-A3B-Instruct.description": "Qwen3-VL-30B-A3B-Instruct هو نموذج Qwen3-VL موجه للتعليمات يتمتع بفهم وتوليد قوي بين الرؤية واللغة. يدعم سياقًا يصل إلى 256 ألف رمز بشكل أصلي للدردشة متعددة الوسائط وتوليد النصوص بناءً على الصور.",
|
||||
"Qwen/Qwen3-VL-30B-A3B-Thinking.description": "Qwen3-VL-30B-A3B-Thinking هو الإصدار المعزز بالاستدلال من Qwen3-VL، مُحسَّن للاستدلال متعدد الوسائط، وتحويل الصور إلى شيفرة، وفهم بصري معقد. يدعم سياقًا يصل إلى 256 ألف رمز مع قدرة أقوى على تسلسل التفكير.",
|
||||
"Qwen/Qwen3-VL-32B-Instruct.description": "Qwen3-VL-32B-Instruct هو نموذج رؤية-لغة من فريق Qwen يحقق نتائج رائدة في اختبارات VL متعددة. يدعم صورًا بدقة ميغابيكسل ويوفر فهمًا بصريًا قويًا، والتعرف البصري متعدد اللغات، وتحديد دقيق للعناصر البصرية، وحوارًا بصريًا. يتعامل مع مهام متعددة الوسائط معقدة ويدعم استدعاء الأدوات وإكمال المقدمات.",
|
||||
@@ -189,6 +183,7 @@
|
||||
"Qwen/Qwen3.5-397B-A17B.description": "Qwen3.5-397B-A17B هو أحدث نموذج رؤية-لغة في سلسلة Qwen3.5، يستخدم بنية Mixture-of-Experts (MoE) مع إجمالي 397 مليار معلمة و17 مليار معلمة مفعلة. يدعم طول سياق 256K مع إمكانية التمديد إلى حوالي مليون رمز، يدعم 201 لغة، ويوفر فهمًا موحدًا للرؤية-اللغة، واستدعاء الأدوات، وقدرات الاستنتاج.",
|
||||
"Qwen/Qwen3.5-4B.description": "Qwen3.5-4B هو نموذج لغة كبير متعدد الوسائط من فريق Qwen مع 4 مليارات معلمة، وهو النموذج الأكثر خفة في سلسلة Qwen3.5. يعتمد على بنية هجينة فعالة تجمع بين شبكات Gated Delta وGated Attention، ويدعم طول سياق 256K مع إمكانية التمديد إلى حوالي مليون رمز.",
|
||||
"Qwen/Qwen3.5-9B.description": "Qwen3.5-9B هو نموذج لغة كبير متعدد الوسائط من فريق Qwen مع 9 مليارات معلمة. كنموذج خفيف الوزن في سلسلة Qwen3.5، يعتمد على بنية هجينة فعالة تجمع بين شبكات Gated Delta وGated Attention، ويدعم طول سياق 256K مع إمكانية التمديد إلى حوالي مليون رمز.",
|
||||
"Qwen/Qwen3.6-27B.description": "Qwen3.6-27B هو أول نموذج متوسط الحجم مفتوح المصدر في سلسلة Qwen3.6، مع تحسينات رئيسية لتوليد الأكواد، تدفقات عمل الوكلاء، وسيناريوهات التطوير الواقعية. مقارنة بـ Qwen3.5-27B، يظهر هذا النموذج تحسينات كبيرة في تطوير الواجهة الأمامية، التفكير على مستوى المستودعات، استدعاء الأدوات، وحل المشكلات المعقدة، مع تحسينات جديدة لقدرات التفكير التاريخي.",
|
||||
"Qwen/Qwen3.6-35B-A3B.description": "يعد Qwen3.6-35B-A3B نموذجاً لغوياً كبيراً من فريق Qwen ضمن سلسلة Qwen3.6، ويعتمد في بنيته على هندسة الخبراء المتعددين (MoE) مع 35 مليار مُعامل إجمالي و3 مليارات مُعامل نشط. يوازن هذا النموذج بين كفاءة الاستدلال والأداء المتميز، ويدعم وضعي التفكير وغير التفكير، مما يسمح بالتنقل المرن بين الاستجابة السريعة والاستدلال العميق.",
|
||||
"Qwen2-72B-Instruct.description": "Qwen2 هو أحدث إصدار من سلسلة Qwen، يدعم نافذة سياق تصل إلى 128 ألف رمز. مقارنة بأفضل النماذج المفتوحة الحالية، يتفوق Qwen2-72B بشكل كبير في فهم اللغة الطبيعية، والمعرفة، والبرمجة، والرياضيات، والقدرات متعددة اللغات.",
|
||||
"Qwen2-7B-Instruct.description": "Qwen2 هو أحدث إصدار من سلسلة Qwen، ويتفوق على أفضل النماذج المفتوحة من نفس الحجم وحتى الأكبر منها. يُظهر Qwen2 7B تفوقًا ملحوظًا في عدة اختبارات، خاصة في البرمجة وفهم اللغة الصينية.",
|
||||
@@ -296,13 +291,11 @@
|
||||
"anthropic/claude-opus-4.description": "Opus 4 هو النموذج الرائد من Anthropic المصمم للمهام المعقدة وتطبيقات المؤسسات.",
|
||||
"anthropic/claude-sonnet-4.5.description": "Claude Sonnet 4.5 هو أحدث نموذج استدلال هجين من Anthropic مُحسَّن للاستدلال المعقد والترميز.",
|
||||
"anthropic/claude-sonnet-4.description": "Claude Sonnet 4 هو نموذج استدلال هجين من Anthropic يجمع بين التفكير وغير التفكير.",
|
||||
"ascend-tribe/pangu-pro-moe.description": "Pangu-Pro-MoE 72B-A16B هو نموذج LLM متفرق يحتوي على 72 مليار معلمة إجمالية و16 مليار نشطة، يعتمد على بنية MoGE. يقوم بتجميع الخبراء أثناء الاختيار ويقيد الرموز لتنشيط عدد متساوٍ من الخبراء لكل مجموعة، مما يوازن الحمل ويحسن كفاءة النشر على Ascend.",
|
||||
"aya.description": "Aya 23 هو نموذج متعدد اللغات من Cohere يدعم 23 لغة لمجموعة متنوعة من الاستخدامات.",
|
||||
"aya:35b.description": "Aya 23 هو نموذج متعدد اللغات من Cohere يدعم 23 لغة لمجموعة متنوعة من الاستخدامات.",
|
||||
"azure-DeepSeek-R1-0528.description": "تم نشره بواسطة Microsoft؛ تم ترقية DeepSeek R1 إلى DeepSeek-R1-0528. يتضمن التحديث تحسينات في الحوسبة وخوارزميات ما بعد التدريب، مما يعزز عمق الاستدلال والاستنتاج بشكل كبير. يتميز بأداء قوي في الرياضيات، والترميز، والمعايير المنطقية العامة، ويقترب من نماذج رائدة مثل O3 وGemini 2.5 Pro.",
|
||||
"baichuan-m2-32b.description": "Baichuan M2 32B هو نموذج MoE من Baichuan Intelligence يتمتع بقدرات استدلال قوية.",
|
||||
"baichuan/baichuan2-13b-chat.description": "Baichuan-13B هو نموذج LLM مفتوح المصدر وقابل للاستخدام التجاري يحتوي على 13 مليار معلمة من Baichuan، يحقق نتائج رائدة في فئته على معايير اللغة الصينية والإنجليزية الموثوقة.",
|
||||
"baidu/ERNIE-4.5-300B-A47B.description": "ERNIE-4.5-300B-A47B هو نموذج MoE من Baidu يحتوي على 300 مليار معلمة إجمالية و47 مليار نشطة لكل رمز، يوازن بين الأداء القوي وكفاءة الحوسبة. كنموذج أساسي في سلسلة ERNIE 4.5، يتميز بالفهم والتوليد والاستدلال والبرمجة. يستخدم طريقة تدريب مسبق متعددة الوسائط غير متجانسة مع تدريب مشترك على النصوص والرؤية لتعزيز القدرات، خاصة في اتباع التعليمات والمعرفة العامة.",
|
||||
"baidu/ernie-5.0-thinking-preview.description": "ERNIE 5.0 Thinking Preview هو نموذج ERNIE متعدد الوسائط من الجيل التالي من Baidu، يتميز بفهم متعدد الوسائط قوي، واتباع التعليمات، والإبداع، والأسئلة والأجوبة الواقعية، واستدعاء الأدوات.",
|
||||
"big-pickle.description": "Big Pickle من OpenCode — نموذج مجاني بوزن مفتوح مع قدرات قوية في البرمجة.",
|
||||
"black-forest-labs/flux-1.1-pro.description": "FLUX 1.1 Pro هو إصدار أسرع ومحسّن من FLUX Pro يتميز بجودة صور ممتازة والتزام دقيق بالتعليمات.",
|
||||
@@ -315,6 +308,7 @@
|
||||
"c4ai-aya-vision-8b.description": "Aya Vision هو نموذج متعدد الوسائط متقدم يقدم أداءً قويًا في اختبارات اللغة والنصوص والرؤية. يركز إصدار 8B على تقليل التأخير مع الحفاظ على أداء قوي.",
|
||||
"charglm-3.description": "CharGLM-3 مصمم للمحادثات التمثيلية والدعم العاطفي، ويدعم ذاكرة طويلة متعددة الأدوار وحوارات مخصصة.",
|
||||
"charglm-4.description": "CharGLM-4 مصمم للمحادثات التمثيلية والدعم العاطفي، ويدعم ذاكرة طويلة متعددة الأدوار وحوارات مخصصة.",
|
||||
"chat-latest.description": "أحدث نموذج فوري مستخدم في ChatGPT.",
|
||||
"chatgpt-4o-latest.description": "ChatGPT-4o هو نموذج ديناميكي يتم تحديثه في الوقت الفعلي. يجمع بين فهم اللغة القوي وتوليدها للاستخدامات واسعة النطاق مثل دعم العملاء والتعليم والمساعدة التقنية.",
|
||||
"claude-2.0.description": "Claude 2 يقدم تحسينات رئيسية للمؤسسات، بما في ذلك سياق 200 ألف رمز، تقليل الهلوسة، دعم التعليمات النظامية، وميزة جديدة: استدعاء الأدوات.",
|
||||
"claude-2.1.description": "Claude 2 يقدم تحسينات رئيسية للمؤسسات، بما في ذلك سياق 200 ألف رمز، تقليل الهلوسة، دعم التعليمات النظامية، وميزة جديدة: استدعاء الأدوات.",
|
||||
@@ -326,13 +320,13 @@
|
||||
"claude-3-haiku-20240307.description": "Claude 3 Haiku هو أسرع وأصغر نموذج من Anthropic، مصمم لتقديم استجابات شبه فورية بأداء سريع ودقيق.",
|
||||
"claude-3-opus-20240229.description": "Claude 3 Opus هو أقوى نموذج من Anthropic للمهام المعقدة، يتميز بالأداء العالي، الذكاء، الطلاقة، والفهم.",
|
||||
"claude-3-sonnet-20240229.description": "Claude 3 Sonnet يوازن بين الذكاء والسرعة لتلبية احتياجات المؤسسات، ويوفر فائدة عالية بتكلفة أقل ونشر موثوق على نطاق واسع.",
|
||||
"claude-haiku-4-5-20251001.description": "Claude Haiku 4.5 هو النموذج الأسرع والأذكى من Anthropic، مع سرعة فائقة وقدرات تفكير ممتدة.",
|
||||
"claude-haiku-4-5-20251001.description": "Claude Haiku 4.5 هو أسرع وأذكى نموذج Haiku من Anthropic، يتميز بسرعة البرق والتفكير الممتد.",
|
||||
"claude-haiku-4-5.description": "Claude Haiku 4.5 من Anthropic — نموذج Haiku من الجيل التالي مع تحسينات في التفكير والرؤية.",
|
||||
"claude-haiku-4.5.description": "Claude Haiku 4.5 هو نموذج Haiku الأسرع والأذكى من Anthropic، يتميز بسرعة البرق وقدرات استدلال موسعة.",
|
||||
"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-1-20250805.description": "Claude Opus 4.1 هو أحدث وأقوى نموذج من Anthropic للمهام المعقدة للغاية، يتميز بالأداء، الذكاء، الطلاقة، والفهم.",
|
||||
"claude-opus-4-1.description": "Claude Opus 4.1 من Anthropic — نموذج تفكير متميز مع قدرات تحليل عميقة.",
|
||||
"claude-opus-4-20250514.description": "Claude Opus 4 هو النموذج الأكثر قوة من Anthropic للمهام المعقدة للغاية، يتفوق في الأداء، الذكاء، الطلاقة، والفهم.",
|
||||
"claude-opus-4-20250514.description": "Claude Opus 4 هو أقوى نموذج من Anthropic للمهام المعقدة للغاية، يتميز بالأداء، الذكاء، الطلاقة، والفهم.",
|
||||
"claude-opus-4-5-20251101.description": "Claude Opus 4.5 هو النموذج الرائد من Anthropic، يجمع بين الذكاء الاستثنائي والأداء القابل للتوسع، مثالي للمهام المعقدة التي تتطلب استجابات عالية الجودة وتفكير متقدم.",
|
||||
"claude-opus-4-5.description": "Claude Opus 4.5 من Anthropic — نموذج رئيسي مع تفكير وبرمجة من الدرجة الأولى.",
|
||||
"claude-opus-4-6.description": "Claude Opus 4.6 من Anthropic — نافذة سياق 1M نموذج رئيسي مع تفكير متقدم.",
|
||||
@@ -341,7 +335,7 @@
|
||||
"claude-opus-4.6-fast.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 يمكنه إنتاج استجابات شبه فورية أو تفكير ممتد خطوة بخطوة مع عملية مرئية.",
|
||||
"claude-sonnet-4-20250514.description": "Claude Sonnet 4 هو النموذج الأكثر ذكاءً من Anthropic حتى الآن، يقدم استجابات شبه فورية أو تفكير ممتد خطوة بخطوة مع تحكم دقيق لمستخدمي API.",
|
||||
"claude-sonnet-4-5-20250929.description": "Claude Sonnet 4.5 هو النموذج الأكثر ذكاءً من Anthropic حتى الآن.",
|
||||
"claude-sonnet-4-5.description": "Claude Sonnet 4.5 من Anthropic — نموذج Sonnet محسّن مع أداء برمجي معزز.",
|
||||
"claude-sonnet-4-6.description": "Claude Sonnet 4.6 من Anthropic — أحدث نموذج Sonnet مع برمجة واستخدام أدوات متفوقة.",
|
||||
@@ -405,24 +399,20 @@
|
||||
"deepseek-ai/DeepSeek-R1-Distill-Llama-70B.description": "تستخدم نماذج DeepSeek-R1 المستخلصة التعلم المعزز وبيانات البداية الباردة لتحسين التفكير وتحديد معايير جديدة للنماذج المفتوحة متعددة المهام.",
|
||||
"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.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 كنموذج وكيل هجين. يعالج المشكلات التي أبلغ عنها المستخدمون ويحسن الاستقرار واتساق اللغة ويقلل من الخلط بين الصينية/الإنجليزية والرموز غير الطبيعية. يدمج أوضاع التفكير وغير التفكير مع قوالب المحادثة للتبديل المرن. كما يعزز أداء وكلاء الكود والبحث لاستخدام الأدوات بشكل أكثر موثوقية وتنفيذ المهام متعددة الخطوات.",
|
||||
"deepseek-ai/DeepSeek-V3.1.description": "يستخدم DeepSeek V3.1 بنية تفكير هجينة ويدعم أوضاع التفكير وغير التفكير.",
|
||||
"deepseek-ai/DeepSeek-V3.2-Exp.description": "DeepSeek V3.2 Exp يستخدم بنية تفكير هجينة ويدعم أوضاع التفكير وغير التفكير.",
|
||||
"deepseek-ai/DeepSeek-V3.2.description": "DeepSeek-V3.2 هو نموذج يجمع بين الكفاءة الحسابية العالية وأداء التفكير والوكيل الممتاز. يعتمد نهجه على ثلاثة اختراقات تكنولوجية رئيسية: DeepSeek Sparse Attention (DSA)، وهي آلية انتباه فعالة تقلل بشكل كبير من التعقيد الحسابي مع الحفاظ على أداء النموذج، ومُحسنة خصيصًا للسيناريوهات ذات السياق الطويل؛ إطار عمل للتعلم المعزز القابل للتوسع يمكن من خلاله أن ينافس أداء النموذج GPT-5، مع نسخته عالية الحوسبة التي تضاهي Gemini-3.0-Pro في قدرات التفكير؛ وخط أنابيب واسع النطاق لتوليف مهام الوكيل يهدف إلى دمج قدرات التفكير في سيناريوهات استخدام الأدوات، مما يحسن اتباع التعليمات والتعميم في البيئات التفاعلية المعقدة. حقق النموذج أداءً متميزًا في الأولمبياد الدولي للرياضيات (IMO) وأولمبياد المعلوماتية الدولي (IOI) لعام 2025.",
|
||||
"deepseek-ai/DeepSeek-V3.description": "DeepSeek-V3 هو نموذج MoE يحتوي على 671 مليار معلمة، يستخدم MLA وDeepSeekMoE مع توازن تحميل خالٍ من الفقدان لتدريب واستدلال فعال. تم تدريبه مسبقًا على 14.8 تريليون رمز عالي الجودة مع SFT وRL، ويتفوق على النماذج المفتوحة الأخرى ويقترب من النماذج المغلقة الرائدة.",
|
||||
"deepseek-ai/DeepSeek-V4-Flash.description": "DeepSeek-V4-Flash هو إصدار معاينة لنموذج اللغة MoE في سلسلة DeepSeek-V4. حجم المعلمات الإجمالي هو 284 مليار، حجم المعلمات النشطة هو 13 مليار، ويدعم سياق طويل للغاية يصل إلى 1 مليون رمز. يستخدم النموذج هيكل انتباه هجين يجمع بين CSA وHCA، ويقدم mHC وMuon Optimizer لتحسين كفاءة التفكير طويل السياق، استقرار التدريب، والأداء العام.",
|
||||
"deepseek-ai/deepseek-llm-67b-chat.description": "DeepSeek LLM Chat (67B) هو نموذج مبتكر يوفر فهمًا عميقًا للغة وتفاعلًا ذكيًا.",
|
||||
"deepseek-ai/deepseek-v3.1-terminus.description": "DeepSeek V3.1 هو نموذج تفكير من الجيل التالي يتمتع بقدرات أقوى في التفكير المعقد وسلسلة التفكير لمهام التحليل العميق.",
|
||||
"deepseek-ai/deepseek-v3.1.description": "DeepSeek V3.1 هو نموذج تفكير من الجيل التالي يتمتع بقدرات أقوى في التفكير المعقد وسلسلة التفكير لمهام التحليل العميق.",
|
||||
"deepseek-ai/deepseek-v3.2.description": "DeepSeek V3.2 هو نموذج استدلال من الجيل التالي يتميز بقدرات استدلال معقدة وسلسلة التفكير.",
|
||||
"deepseek-chat.description": "نموذج مفتوح المصدر جديد يجمع بين القدرات العامة والبرمجية. يحافظ على الحوار العام لنموذج الدردشة وقوة البرمجة لنموذج البرمجة، مع تحسين التوافق مع التفضيلات. DeepSeek-V2.5 يحسن أيضًا الكتابة واتباع التعليمات.",
|
||||
"deepseek-chat.description": "اسم مستعار للتوافق مع وضع عدم التفكير في DeepSeek V4 Flash. مقرر إيقافه — استخدم DeepSeek V4 Flash بدلاً منه.",
|
||||
"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.",
|
||||
"deepseek-ocr.description": "DeepSeek-OCR هو نموذج رؤية-لغة من DeepSeek AI يركز على OCR و\"الضغط البصري السياقي\". يستكشف ضغط المعلومات السياقية من الصور، ويعالج المستندات بكفاءة، ويحولها إلى تنسيقات نصية منظمة مثل Markdown. يتعرف بدقة على النصوص في الصور، مما يجعله مثاليًا لتحويل المستندات إلى صيغة رقمية، واستخراج النصوص، والمعالجة المنظمة.",
|
||||
"deepseek-r1-0528.description": "نموذج كامل بسعة 685 مليار تم إصداره في 28 مايو 2025. يستخدم DeepSeek-R1 التعلم المعزز واسع النطاق بعد التدريب، مما يعزز التفكير بشكل كبير باستخدام بيانات معنونة قليلة، ويؤدي أداءً قويًا في الرياضيات، والبرمجة، والتفكير باللغة الطبيعية.",
|
||||
"deepseek-r1-250528.description": "DeepSeek R1 250528 هو النموذج الكامل للتفكير من DeepSeek-R1 للمهام الرياضية والمنطقية الصعبة.",
|
||||
"deepseek-r1-70b-fast-online.description": "إصدار سريع من DeepSeek R1 70B مع بحث ويب في الوقت الحقيقي، يوفر استجابات أسرع مع الحفاظ على الأداء.",
|
||||
@@ -441,7 +431,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 V4. مقرر إيقافه — استخدم deepseek-v4-flash بدلاً منه.",
|
||||
"deepseek-reasoner.description": "اسم مستعار للتوافق مع وضع التفكير في DeepSeek V4 Flash. مقرر إيقافه — استخدم DeepSeek V4 Flash بدلاً منه.",
|
||||
"deepseek-v2.description": "DeepSeek V2 هو نموذج MoE فعال لمعالجة منخفضة التكلفة.",
|
||||
"deepseek-v2:236b.description": "DeepSeek V2 236B هو نموذج DeepSeek الموجه للبرمجة مع قدرات قوية في توليد الكود.",
|
||||
"deepseek-v3-0324.description": "DeepSeek-V3-0324 هو نموذج MoE يحتوي على 671 مليار معلمة يتميز بقوة في البرمجة، والقدرات التقنية، وفهم السياق، والتعامل مع النصوص الطويلة.",
|
||||
@@ -460,19 +450,16 @@
|
||||
"deepseek-vl2-small.description": "DeepSeek VL2 Small هو إصدار متعدد الوسائط خفيف الوزن للاستخدام في البيئات ذات الموارد المحدودة أو التزامن العالي.",
|
||||
"deepseek-vl2.description": "DeepSeek VL2 هو نموذج متعدد الوسائط لفهم النصوص والصور والإجابة البصرية الدقيقة.",
|
||||
"deepseek/deepseek-chat-v3-0324.description": "DeepSeek V3 هو نموذج MoE يحتوي على 685 مليار معلمة، وهو أحدث إصدار من سلسلة دردشة DeepSeek الرائدة.\n\nيعتمد على [DeepSeek V3](/deepseek/deepseek-chat-v3) ويؤدي أداءً قويًا عبر المهام.",
|
||||
"deepseek/deepseek-chat-v3-0324:free.description": "DeepSeek V3 هو نموذج MoE يحتوي على 685 مليار معلمة، وهو أحدث إصدار من سلسلة دردشة DeepSeek الرائدة.\n\nيعتمد على [DeepSeek V3](/deepseek/deepseek-chat-v3) ويؤدي أداءً قويًا عبر المهام.",
|
||||
"deepseek/deepseek-chat-v3.1.description": "DeepSeek-V3.1 هو نموذج استدلال هجين طويل السياق من DeepSeek، يدعم أوضاع التفكير وغير التفكير ودمج الأدوات.",
|
||||
"deepseek/deepseek-chat.description": "DeepSeek-V3 هو نموذج استدلال هجين عالي الأداء من DeepSeek للمهام المعقدة ودمج الأدوات.",
|
||||
"deepseek/deepseek-math-v2.description": "DeepSeek Math V2 هو نموذج حقق تقدمًا كبيرًا في قدرات الاستدلال الرياضي. تكمن ابتكاره الأساسي في آلية التدريب \"التحقق الذاتي\"، وقد حصل على مستويات ميدالية ذهبية في العديد من المسابقات الرياضية العالمية.",
|
||||
"deepseek/deepseek-r1-0528.description": "DeepSeek R1 0528 هو إصدار محدث يركز على الإتاحة المفتوحة والاستدلال الأعمق.",
|
||||
"deepseek/deepseek-r1-0528:free.description": "يحسن DeepSeek-R1 الاستدلال بشكل كبير باستخدام بيانات معنونة قليلة، ويخرج سلسلة من الأفكار قبل الإجابة النهائية لتحسين الدقة.",
|
||||
"deepseek/deepseek-r1-distill-llama-70b.description": "DeepSeek R1 Distill Llama 70B هو نموذج LLM مكرر يعتمد على Llama 3.3 70B، تم تحسينه باستخدام مخرجات DeepSeek R1 لتحقيق أداء تنافسي مع النماذج الرائدة.",
|
||||
"deepseek/deepseek-r1-distill-llama-8b.description": "DeepSeek R1 Distill Llama 8B هو نموذج LLM مكرر يعتمد على Llama-3.1-8B-Instruct، تم تدريبه باستخدام مخرجات DeepSeek R1.",
|
||||
"deepseek/deepseek-r1-distill-qwen-14b.description": "DeepSeek R1 Distill Qwen 14B هو نموذج LLM مكرر يعتمد على Qwen 2.5 14B، تم تدريبه باستخدام مخرجات DeepSeek R1. يتفوق على OpenAI o1-mini في العديد من المعايير، ويحقق نتائج رائدة بين النماذج الكثيفة.",
|
||||
"deepseek/deepseek-r1-distill-qwen-32b.description": "DeepSeek R1 Distill Qwen 32B هو نموذج LLM مكرر يعتمد على Qwen 2.5 32B، تم تدريبه باستخدام مخرجات DeepSeek R1. يتفوق على OpenAI o1-mini في العديد من المعايير، ويحقق نتائج رائدة بين النماذج الكثيفة.",
|
||||
"deepseek/deepseek-r1.description": "تم تحديث DeepSeek R1 إلى DeepSeek-R1-0528. مع موارد حوسبة أكبر وتحسينات خوارزمية بعد التدريب، يعزز بشكل كبير عمق وقدرة الاستدلال. يؤدي أداءً قويًا في اختبارات الرياضيات، البرمجة، والمنطق العام، ويقترب من نماذج رائدة مثل o3 وGemini 2.5 Pro.",
|
||||
"deepseek/deepseek-r1/community.description": "DeepSeek R1 هو أحدث نموذج مفتوح المصدر من فريق DeepSeek، يتميز بأداء استدلال قوي، خاصة في الرياضيات، البرمجة، ومهام التفكير، ويقارن بـ OpenAI o1.",
|
||||
"deepseek/deepseek-r1:free.description": "يحسن DeepSeek-R1 الاستدلال بشكل كبير باستخدام بيانات معنونة قليلة، ويخرج سلسلة من الأفكار قبل الإجابة النهائية لتحسين الدقة.",
|
||||
"deepseek/deepseek-reasoner.description": "DeepSeek-V3 Thinking (reasoner) هو نموذج استدلال تجريبي من DeepSeek، مناسب للمهام المعقدة.",
|
||||
"deepseek/deepseek-v3.description": "نموذج لغوي عام سريع مع استدلال محسّن.",
|
||||
"deepseek/deepseek-v3/community.description": "يُقدّم DeepSeek-V3 تقدمًا كبيرًا في سرعة الاستدلال مقارنة بالإصدارات السابقة. يحتل المرتبة الأولى بين النماذج مفتوحة المصدر ويضاهي أكثر النماذج المغلقة تقدمًا. يعتمد DeepSeek-V3 على آلية الانتباه الكامن متعدد الرؤوس (MLA) وبنية DeepSeekMoE، وكلاهما تم التحقق منه بالكامل في DeepSeek-V2. كما يُدخل استراتيجية مساعدة غير فقدية لتحقيق توازن في التحميل، وهدف تدريب على التنبؤ بعدة رموز لتعزيز الأداء.",
|
||||
@@ -485,18 +472,11 @@
|
||||
"doubao-1.5-lite-32k.description": "Doubao-1.5-lite هو نموذج خفيف الوزن جديد يتميز بسرعة استجابة فائقة، ويقدم جودة عالية وأداء منخفض الكمون من الدرجة الأولى.",
|
||||
"doubao-1.5-pro-256k.description": "Doubao-1.5-pro-256k هو ترقية شاملة لـ Doubao-1.5-Pro، حيث يحسن الأداء العام بنسبة 10٪. يدعم نافذة سياق بحجم 256k وما يصل إلى 12k من الرموز الناتجة، مما يوفر أداءً أعلى، وسياقًا أوسع، وقيمة قوية لحالات الاستخدام المتنوعة.",
|
||||
"doubao-1.5-pro-32k.description": "Doubao-1.5-pro هو نموذج رائد من الجيل الجديد يتميز بترقيات شاملة، ويتفوق في المعرفة والبرمجة والاستدلال.",
|
||||
"doubao-1.5-thinking-pro-m.description": "Doubao-1.5 هو نموذج جديد للاستدلال العميق (الإصدار m يدعم الاستدلال العميق متعدد الوسائط بشكل أصلي) ويتفوق في الرياضيات والبرمجة والاستدلال العلمي والمهام العامة مثل الكتابة الإبداعية. يحقق نتائج من الدرجة الأولى أو يقترب منها في معايير مثل AIME 2024 وCodeforces وGPQA. يدعم نافذة سياق بحجم 128k وما يصل إلى 16k من الرموز الناتجة.",
|
||||
"doubao-1.5-thinking-pro.description": "Doubao-1.5 هو نموذج جديد للاستدلال العميق يتفوق في الرياضيات والبرمجة والاستدلال العلمي والمهام العامة مثل الكتابة الإبداعية. يحقق نتائج من الدرجة الأولى أو يقترب منها في معايير مثل AIME 2024 وCodeforces وGPQA. يدعم نافذة سياق بحجم 128k وما يصل إلى 16k من الرموز الناتجة.",
|
||||
"doubao-1.5-thinking-vision-pro.description": "نموذج جديد للاستدلال البصري العميق يتمتع بفهم واستدلال متعدد الوسائط أقوى، ويحقق نتائج رائدة في 37 من أصل 59 معيارًا عامًا.",
|
||||
"doubao-1.5-ui-tars.description": "Doubao-1.5-UI-TARS هو نموذج وكيل يركز على واجهات المستخدم الرسومية (GUI) ويتفاعل بسلاسة مع الواجهات من خلال الإدراك البشري، والاستدلال، والعمل.",
|
||||
"doubao-1.5-vision-lite.description": "Doubao-1.5-vision-lite هو نموذج متعدد الوسائط مطور يدعم الصور بأي دقة ونسب أبعاد متطرفة، مما يعزز الاستدلال البصري، والتعرف على المستندات، وفهم التفاصيل، واتباع التعليمات. يدعم نافذة سياق بحجم 128k وما يصل إلى 16k من الرموز الناتجة.",
|
||||
"doubao-1.5-vision-pro-32k.description": "Doubao-1.5-vision-pro هو نموذج متعدد الوسائط مطور يدعم الصور بأي دقة ونسب أبعاد متطرفة، مما يعزز الاستدلال البصري، والتعرف على المستندات، وفهم التفاصيل، واتباع التعليمات.",
|
||||
"doubao-1.5-vision-pro.description": "Doubao-1.5-vision-pro هو نموذج متعدد الوسائط مطور يدعم الصور بأي دقة ونسب أبعاد متطرفة، مما يعزز الاستدلال البصري، والتعرف على المستندات، وفهم التفاصيل، واتباع التعليمات.",
|
||||
"doubao-lite-32k.description": "استجابة فائقة السرعة مع قيمة أفضل، توفر خيارات أكثر مرونة عبر السيناريوهات. يدعم الاستدلال والتخصيص الدقيق مع نافذة سياق بحجم 32k.",
|
||||
"doubao-pro-32k.description": "أفضل نموذج رائد للأداء في المهام المعقدة، مع نتائج قوية في الأسئلة المرجعية، والتلخيص، والإبداع، وتصنيف النصوص، والمحاكاة. يدعم الاستدلال والتخصيص الدقيق مع نافذة سياق بحجم 32k.",
|
||||
"doubao-seed-1.6-flash.description": "Doubao-Seed-1.6-flash هو نموذج استدلال عميق متعدد الوسائط فائق السرعة بزمن معالجة منخفض يصل إلى 10 مللي ثانية. يدعم النصوص والرؤية، ويتفوق على النموذج الخفيف السابق في فهم النصوص، ويضاهي النماذج الاحترافية المنافسة في الرؤية. يدعم نافذة سياق بحجم 256k وما يصل إلى 16k من الرموز الناتجة.",
|
||||
"doubao-seed-1.6-lite.description": "Doubao-Seed-1.6-lite هو نموذج استدلال عميق متعدد الوسائط جديد مع جهد استدلال قابل للتعديل (أدنى، منخفض، متوسط، عالٍ)، يوفر قيمة أفضل وخيارًا قويًا للمهام الشائعة، مع نافذة سياق تصل إلى 256k.",
|
||||
"doubao-seed-1.6-thinking.description": "يعزز Doubao-Seed-1.6-thinking قدرات الاستدلال بشكل كبير، ويحسن القدرات الأساسية في البرمجة والرياضيات والمنطق مقارنة بـ Doubao-1.5-thinking-pro، مع إضافة فهم بصري. يدعم نافذة سياق بحجم 256k وما يصل إلى 16k من الرموز الناتجة.",
|
||||
"doubao-seed-1.6-vision.description": "Doubao-Seed-1.6-vision هو نموذج استدلال بصري عميق يوفر فهمًا واستدلالًا متعدد الوسائط أقوى للتعليم، ومراجعة الصور، والتفتيش/الأمن، والبحث الذكي. يدعم نافذة سياق بحجم 256k وما يصل إلى 64k من الرموز الناتجة.",
|
||||
"doubao-seed-1.6.description": "Doubao-Seed-1.6 هو نموذج استدلال عميق متعدد الوسائط جديد يدعم أوضاع التفكير التلقائي، والتفكير، وعدم التفكير. في وضع عدم التفكير، يتفوق بشكل كبير على Doubao-1.5-pro/250115. يدعم نافذة سياق بحجم 256k وما يصل إلى 16k من الرموز الناتجة.",
|
||||
"doubao-seed-1.8.description": "Doubao-Seed-1.8 يتمتع بفهم متعدد الوسائط أقوى وقدرات وكيل متقدمة، ويدعم إدخال النصوص/الصور/الفيديو وتخزين السياق المؤقت، ويقدم أداءً ممتازًا في المهام المعقدة.",
|
||||
@@ -512,31 +492,25 @@
|
||||
"doubao-seedance-1-5-pro-251215.description": "Seedance 1.5 Pro من ByteDance يدعم تحويل النص إلى فيديو، الصورة إلى فيديو (الإطار الأول، الإطار الأول + الأخير)، وتوليد الصوت المتزامن مع المرئيات.",
|
||||
"doubao-seedance-2-0-260128.description": "Seedance 2.0 من ByteDance هو النموذج الأقوى لإنشاء الفيديو، يدعم إنشاء الفيديو متعدد الوسائط، وتحرير الفيديو، وتمديد الفيديو، وتحويل النص إلى فيديو، وتحويل الصور إلى فيديو مع صوت متزامن.",
|
||||
"doubao-seedance-2-0-fast-260128.description": "Seedance 2.0 Fast من ByteDance يقدم نفس القدرات مثل Seedance 2.0 مع سرعات إنشاء أسرع وسعر أكثر تنافسية.",
|
||||
"doubao-seededit-3-0-i2i-250628.description": "نموذج الصور Doubao من ByteDance Seed يدعم إدخال النصوص والصور مع توليد صور عالية الجودة وقابلة للتحكم بدرجة كبيرة. يدعم تحرير الصور الموجه بالنص، مع أحجام إخراج تتراوح بين 512 و1536 على الجانب الطويل.",
|
||||
"doubao-seedream-3-0-t2i-250415.description": "Seedream 3.0 هو نموذج توليد صور من ByteDance Seed، يدعم إدخال النصوص والصور مع توليد صور عالية الجودة وقابلة للتحكم بدرجة كبيرة. يُولّد الصور من التعليمات النصية.",
|
||||
"doubao-seedream-4-0-250828.description": "Seedream 4.0 هو نموذج توليد صور من ByteDance Seed، يدعم إدخال النصوص والصور مع توليد صور عالية الجودة وقابلة للتحكم بدرجة كبيرة. يُولّد الصور من التعليمات النصية.",
|
||||
"doubao-seedream-4-5-251128.description": "Seedream 4.5 هو أحدث نموذج متعدد الوسائط من ByteDance، يدمج قدرات تحويل النص إلى صورة، والصورة إلى صورة، وتوليد الصور بالجملة، مع دمج الفهم العام وقدرات الاستدلال. مقارنة بالإصدار السابق 4.0، يقدم جودة توليد محسّنة بشكل كبير، مع تحسين تناسق التحرير ودمج الصور المتعددة. يوفر تحكمًا أكثر دقة في التفاصيل البصرية، مما يجعل النصوص الصغيرة والوجوه الصغيرة أكثر طبيعية، ويحقق تخطيطًا وألوانًا أكثر انسجامًا، مما يعزز الجماليات العامة.",
|
||||
"doubao-seedream-5-0-260128.description": "Doubao-Seedream-5.0-lite هو أحدث نموذج لتوليد الصور من ByteDance. لأول مرة، يدمج قدرات الاسترجاع عبر الإنترنت، مما يسمح له بتضمين معلومات الويب في الوقت الفعلي وتعزيز حداثة الصور المولدة. كما تم ترقية ذكاء النموذج، مما يمكنه من تفسير التعليمات المعقدة والمحتوى البصري بدقة. بالإضافة إلى ذلك، يقدم تغطية محسّنة للمعرفة العالمية، وتناسقًا مرجعيًا، وجودة توليد في السيناريوهات المهنية، مما يلبي بشكل أفضل احتياجات الإبداع البصري على مستوى المؤسسات.",
|
||||
"dreamina-seedance-2-0-260128.description": "Seedance 2.0 من ByteDance هو النموذج الأكثر قوة لتوليد الفيديو، يدعم إنشاء فيديو مرجعي متعدد الوسائط، تحرير الفيديو، تمديد الفيديو، تحويل النص إلى فيديو، وتحويل الصورة إلى فيديو مع صوت متزامن.",
|
||||
"dreamina-seedance-2-0-fast-260128.description": "Seedance 2.0 Fast من ByteDance يقدم نفس القدرات مثل Seedance 2.0 مع سرعات توليد أسرع وسعر أكثر تنافسية.",
|
||||
"emohaa.description": "Emohaa هو نموذج للصحة النفسية يتمتع بقدرات استشارية احترافية لمساعدة المستخدمين على فهم المشكلات العاطفية.",
|
||||
"ernie-4.5-0.3b.description": "ERNIE 4.5 0.3B هو نموذج مفتوح المصدر وخفيف الوزن، مصمم للنشر المحلي والمخصص.",
|
||||
"ernie-4.5-21b-a3b-thinking.description": "ERNIE-4.5-21B-A3B-Thinking هو نموذج نصي MoE (مزيج من الخبراء) مدرب بعديًا مع إجمالي 21 مليار معلمة و3 مليارات معلمة نشطة، يقدم جودة وعمق استدلال محسّنة بشكل كبير.",
|
||||
"ernie-4.5-21b-a3b.description": "ERNIE 4.5 21B A3B هو نموذج مفتوح المصدر ذو عدد كبير من المعلمات، يتميز بفهم وتوليد أقوى.",
|
||||
"ernie-4.5-300b-a47b.description": "ERNIE 4.5 300B A47B هو نموذج MoE فائق الحجم من Baidu ERNIE يتمتع بقدرات استدلال ممتازة.",
|
||||
"ernie-4.5-8k-preview.description": "ERNIE 4.5 8K Preview هو نموذج معاينة بسياق 8K لتقييم أداء ERNIE 4.5.",
|
||||
"ernie-4.5-turbo-128k-preview.description": "معاينة ERNIE 4.5 Turbo 128K بقدرات على مستوى الإصدار، مناسبة للتكامل والاختبار التجريبي.",
|
||||
"ernie-4.5-turbo-128k.description": "ERNIE 4.5 Turbo 128K هو نموذج عام عالي الأداء يدعم تعزيز البحث واستدعاء الأدوات لسيناريوهات الأسئلة والأجوبة، والبرمجة، والوكلاء.",
|
||||
"ernie-4.5-turbo-20260402.description": "ERNIE 4.5 Turbo 20260402 هو نموذج عام عالي الأداء مع تعزيز البحث واستدعاء الأدوات لسيناريوهات الأسئلة والأجوبة، البرمجة، ووكلاء الذكاء الاصطناعي.",
|
||||
"ernie-4.5-turbo-32k.description": "ERNIE 4.5 Turbo 32K هو إصدار متوسط الطول من السياق مخصص للأسئلة والأجوبة، واسترجاع قواعد المعرفة، والحوار متعدد الأدوار.",
|
||||
"ernie-4.5-turbo-latest.description": "أحدث إصدار من ERNIE 4.5 Turbo بأداء محسن شامل، مثالي كنموذج إنتاج رئيسي.",
|
||||
"ernie-4.5-turbo-vl-32k-preview.description": "معاينة ERNIE 4.5 Turbo VL 32K هو نموذج متعدد الوسائط بسياق طويل لتقييم قدرات الرؤية.",
|
||||
"ernie-4.5-turbo-vl-32k.description": "ERNIE 4.5 Turbo VL 32K هو إصدار متعدد الوسائط متوسط الطول لفهم المستندات الطويلة والصور معًا.",
|
||||
"ernie-4.5-turbo-vl-latest.description": "أحدث إصدار من ERNIE 4.5 Turbo VL متعدد الوسائط مع تحسينات في فهم الصور والنصوص والاستدلال.",
|
||||
"ernie-4.5-turbo-vl-preview.description": "معاينة ERNIE 4.5 Turbo VL هو نموذج متعدد الوسائط لفهم وتوليد الصور والنصوص، مناسب لأسئلة وأجوبة بصرية وفهم المحتوى.",
|
||||
"ernie-4.5-turbo-vl.description": "ERNIE 4.5 Turbo VL هو نموذج متعدد الوسائط ناضج لفهم الصور والنصوص في بيئات الإنتاج.",
|
||||
"ernie-4.5-vl-28b-a3b.description": "ERNIE 4.5 VL 28B A3B هو نموذج مفتوح المصدر متعدد الوسائط لفهم الصور والنصوص والاستدلال.",
|
||||
"ernie-5.0-thinking-latest.description": "Wenxin 5.0 Thinking هو نموذج رائد متعدد الوسائط أصلي يدعم النصوص، الصور، الصوت، والفيديو بشكل موحد. يوفر ترقيات شاملة للقدرات في الأسئلة المعقدة، الإبداع، وسيناريوهات الوكلاء.",
|
||||
"ernie-5.0-thinking-preview.description": "معاينة Wenxin 5.0 Thinking هو نموذج رائد متعدد الوسائط أصلي يدعم النصوص، الصور، الصوت، والفيديو بشكل موحد. يوفر ترقيات شاملة للقدرات في الأسئلة المعقدة، الإبداع، وسيناريوهات الوكلاء.",
|
||||
"ernie-5.0.description": "ERNIE 5.0، النموذج الجديد في سلسلة ERNIE، هو نموذج كبير متعدد الوسائط أصلي. يعتمد نهج نمذجة متعدد الوسائط موحد، حيث يقوم بنمذجة النصوص، الصور، الصوت، والفيديو بشكل مشترك لتقديم قدرات متعددة الوسائط شاملة. تم تحسين قدراته الأساسية بشكل كبير، محققًا أداءً قويًا في تقييمات المعايير. يتفوق بشكل خاص في الفهم متعدد الوسائط، اتباع التعليمات، الكتابة الإبداعية، الدقة الواقعية، تخطيط الوكلاء، واستخدام الأدوات.",
|
||||
"ernie-char-8k.description": "ERNIE Character 8K هو نموذج حواري بشخصية مخصصة لبناء شخصيات IP والدردشة طويلة الأمد.",
|
||||
"ernie-char-fiction-8k-preview.description": "معاينة ERNIE Character Fiction 8K هو نموذج لإنشاء الشخصيات والحبكات القصصية، مخصص لتقييم الميزات والاختبار.",
|
||||
"ernie-char-fiction-8k.description": "ERNIE Character Fiction 8K هو نموذج شخصيات للروايات وإنشاء الحبكات، مناسب لتوليد القصص الطويلة.",
|
||||
"ernie-image-turbo.description": "ERNIE-Image هو نموذج نص إلى صورة بـ 8 مليارات معلمة تم تطويره بواسطة Baidu. يحتل المرتبة الأولى في العديد من المعايير، محققًا المركز الأول في SuperCLUE في الصين ويتصدر المسار مفتوح المصدر.",
|
||||
@@ -548,7 +522,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.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] هو نموذج لتوليد الصور يتميز بميول جمالية نحو صور أكثر واقعية وطبيعية.",
|
||||
@@ -556,8 +531,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-kontext-max.description": "توليد وتحرير صور سياقية متقدمة، تجمع بين النصوص والصور لتحقيق نتائج دقيقة ومتسقة.",
|
||||
@@ -572,7 +547,6 @@
|
||||
"gemini-1.5-flash-001.description": "Gemini 1.5 Flash 001 هو نموذج متعدد الوسائط فعال لتوسيع التطبيقات على نطاق واسع.",
|
||||
"gemini-1.5-flash-002.description": "Gemini 1.5 Flash 002 هو نموذج متعدد الوسائط فعال مصمم للنشر الواسع.",
|
||||
"gemini-1.5-flash-8b-exp-0924.description": "Gemini 1.5 Flash 8B 0924 هو أحدث نموذج تجريبي يحقق مكاسب ملحوظة في استخدامات النصوص والمتعددة الوسائط.",
|
||||
"gemini-1.5-flash-8b-latest.description": "Gemini 1.5 Flash 8B هو نموذج متعدد الوسائط فعال مصمم للنشر الواسع.",
|
||||
"gemini-1.5-flash-8b.description": "Gemini 1.5 Flash 8B هو نموذج متعدد الوسائط فعال لتوسيع التطبيقات على نطاق واسع.",
|
||||
"gemini-1.5-flash-exp-0827.description": "Gemini 1.5 Flash 0827 يقدم معالجة متعددة الوسائط محسّنة للمهام المعقدة.",
|
||||
"gemini-1.5-flash-latest.description": "Gemini 1.5 Flash هو أحدث نموذج ذكاء اصطناعي متعدد الوسائط من Google يتميز بمعالجة سريعة ويدعم إدخال النصوص والصور والفيديو لتوسيع المهام بكفاءة.",
|
||||
@@ -588,7 +562,6 @@
|
||||
"gemini-2.5-flash-image.description": "Nano Banana هو أحدث وأسرع وأكثر نماذج Google متعددة الوسائط كفاءة، يتيح توليد الصور وتحريرها عبر المحادثة.",
|
||||
"gemini-2.5-flash-image:image.description": "Nano Banana هو أحدث وأسرع وأكثر نماذج Google متعددة الوسائط كفاءة، يتيح توليد الصور وتحريرها عبر المحادثة.",
|
||||
"gemini-2.5-flash-lite-preview-06-17.description": "Gemini 2.5 Flash-Lite Preview هو أصغر نموذج من Google وأفضلها من حيث القيمة، مصمم للاستخدام واسع النطاق.",
|
||||
"gemini-2.5-flash-lite-preview-09-2025.description": "إصدار معاينة (25 سبتمبر 2025) من Gemini 2.5 Flash-Lite",
|
||||
"gemini-2.5-flash-lite.description": "Gemini 2.5 Flash-Lite هو أصغر نموذج من Google وأفضلها من حيث القيمة، مصمم للاستخدام واسع النطاق.",
|
||||
"gemini-2.5-flash-preview-04-17.description": "Gemini 2.5 Flash Preview هو أفضل نموذج من Google من حيث القيمة مع قدرات كاملة.",
|
||||
"gemini-2.5-flash.description": "Gemini 2.5 Flash هو أفضل نموذج من Google من حيث القيمة مع قدرات كاملة.",
|
||||
@@ -601,13 +574,13 @@
|
||||
"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) هو أسرع نموذج توليد الصور الأصلي من Google مع دعم التفكير، توليد الصور التفاعلية وتحريرها.",
|
||||
"gemini-3.1-flash-image-preview:image.description": "Gemini 3.1 Flash Image (Nano Banana 2) يقدم جودة صور احترافية بسرعة 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-3.1-pro.description": "Gemini 3.1 Pro من Google — نموذج متعدد الوسائط متميز مع نافذة سياق 1M.",
|
||||
"gemini-flash-latest.description": "أحدث إصدار من Gemini Flash",
|
||||
"gemini-flash-lite-latest.description": "أحدث إصدار من Gemini Flash-Lite",
|
||||
"gemini-pro-latest.description": "أحدث إصدار من Gemini Pro",
|
||||
"gemini-flash-latest.description": "يشير إلى gemini-3-flash-preview",
|
||||
"gemini-flash-lite-latest.description": "يشير إلى gemini-2.5-flash-lite-preview-09-2025",
|
||||
"gemini-pro-latest.description": "يشير إلى gemini-3.1-pro-preview",
|
||||
"gemma-7b-it.description": "Gemma 7B فعال من حيث التكلفة للمهام الصغيرة والمتوسطة.",
|
||||
"gemma2-9b-it.description": "Gemma 2 9B مُحسّن للمهام المحددة وتكامل الأدوات.",
|
||||
"gemma2.description": "Gemma 2 هو نموذج فعال من Google يغطي حالات الاستخدام من التطبيقات الصغيرة إلى معالجة البيانات المعقدة.",
|
||||
@@ -668,8 +641,6 @@
|
||||
"google/gemini-2.0-flash.description": "Gemini 2.0 Flash هو نموذج استدلال عالي الأداء من Google للمهام متعددة الوسائط الممتدة.",
|
||||
"google/gemini-2.5-flash-image.description": "Gemini 2.5 Flash Image (Nano Banana) هو نموذج توليد الصور من Google مع دعم المحادثة متعددة الوسائط.",
|
||||
"google/gemini-2.5-flash-lite.description": "Gemini 2.5 Flash Lite هو إصدار خفيف من Gemini 2.5 محسّن لزمن الاستجابة والتكلفة، مناسب لسيناريوهات الإنتاجية العالية.",
|
||||
"google/gemini-2.5-flash-preview.description": "Gemini 2.5 Flash هو النموذج الرائد الأكثر تقدمًا من Google، مصمم لمهام الاستدلال المتقدم، البرمجة، الرياضيات، والعلوم. يتضمن ميزة \"التفكير\" المدمجة لتقديم استجابات أكثر دقة ومعالجة سياق أدق.\n\nملاحظة: يحتوي هذا النموذج على نسختين — مع التفكير وبدونه. تختلف أسعار الإخراج بشكل كبير حسب ما إذا كان التفكير مفعلاً. إذا اخترت النسخة القياسية (بدون اللاحقة \":thinking\")، سيتجنب النموذج توليد رموز التفكير.\n\nلاستخدام التفكير واستلام رموز التفكير، يجب اختيار النسخة \":thinking\"، والتي تتطلب تكلفة أعلى.\n\nيمكن أيضًا ضبط Gemini 2.5 Flash عبر معلمة \"الحد الأقصى لرموز الاستدلال\" كما هو موضح في الوثائق (https://openrouter.ai/docs/use-cases/reasoning-tokens#max-tokens-for-reasoning).",
|
||||
"google/gemini-2.5-flash-preview:thinking.description": "Gemini 2.5 Flash هو النموذج الرائد الأكثر تقدمًا من Google، مصمم لمهام الاستدلال المتقدم، البرمجة، الرياضيات، والعلوم. يتضمن ميزة \"التفكير\" المدمجة لتقديم استجابات أكثر دقة ومعالجة سياق أدق.\n\nملاحظة: يحتوي هذا النموذج على نسختين — مع التفكير وبدونه. تختلف أسعار الإخراج بشكل كبير حسب ما إذا كان التفكير مفعلاً. إذا اخترت النسخة القياسية (بدون اللاحقة \":thinking\"), سيتجنب النموذج توليد رموز التفكير.\n\nلاستخدام التفكير واستلام رموز التفكير، يجب اختيار النسخة \":thinking\"، والتي تتطلب تكلفة أعلى.\n\nيمكن أيضًا ضبط Gemini 2.5 Flash عبر معلمة \"الحد الأقصى لرموز الاستدلال\" كما هو موضح في الوثائق (https://openrouter.ai/docs/use-cases/reasoning-tokens#max-tokens-for-reasoning).",
|
||||
"google/gemini-2.5-flash.description": "Gemini 2.5 Flash هو عائلة Google التي تمتد من زمن استجابة منخفض إلى أداء عالٍ في التفكير.",
|
||||
"google/gemini-2.5-pro-preview.description": "Gemini 2.5 Pro Preview هو النموذج الأكثر تقدمًا من Google للاستدلال في المشكلات المعقدة في البرمجة، الرياضيات، والعلوم، وتحليل مجموعات البيانات الكبيرة، قواعد الشيفرة، والمستندات ذات السياق الطويل.",
|
||||
"google/gemini-2.5-pro.description": "Gemini 2.5 Pro هو النموذج الرائد من Google للاستدلال مع دعم السياق الطويل للمهام المعقدة.",
|
||||
@@ -677,13 +648,10 @@
|
||||
"google/gemini-3-pro-preview.description": "Gemini 3 Pro هو نموذج الاستدلال متعدد الوسائط من الجيل التالي في عائلة Gemini، يفهم النصوص، الصوت، الصور، والفيديو، ويتعامل مع المهام المعقدة وقواعد الشيفرة الكبيرة.",
|
||||
"google/gemini-3.1-flash-image-preview.description": "Gemini 3.1 Flash Image Preview، المعروف أيضًا باسم \"Nano Banana 2\"، هو أحدث نموذج من Google لإنشاء الصور وتحريرها، يقدم جودة بصرية بمستوى احترافي بسرعة Flash. يجمع بين فهم السياق المتقدم والاستدلال السريع والفعال من حيث التكلفة، مما يجعل إنشاء الصور المعقدة والتعديلات التكرارية أكثر سهولة بشكل كبير.",
|
||||
"google/gemini-embedding-001.description": "نموذج تضمين متقدم يتميز بأداء قوي في مهام اللغة الإنجليزية، ومتعددة اللغات، والبرمجة.",
|
||||
"google/gemini-flash-1.5.description": "يوفر Gemini 1.5 Flash معالجة متعددة الوسائط محسّنة لمجموعة من المهام المعقدة.",
|
||||
"google/gemini-pro-1.5.description": "يجمع Gemini 1.5 Pro بين أحدث التحسينات لمعالجة أكثر كفاءة للبيانات متعددة الوسائط.",
|
||||
"google/gemma-2-27b-it.description": "Gemma 2 27B هو نموذج لغوي عام الأداء يتميز بقوة في العديد من السيناريوهات.",
|
||||
"google/gemma-2-27b.description": "Gemma 2 هي عائلة نماذج فعالة من Google تناسب التطبيقات الصغيرة ومعالجة البيانات المعقدة.",
|
||||
"google/gemma-2-2b-it.description": "نموذج لغوي صغير متقدم مصمم لتطبيقات الحافة.",
|
||||
"google/gemma-2-9b-it.description": "Gemma 2 9B، من تطوير Google، يقدم اتباع تعليمات فعال وقدرات عامة قوية.",
|
||||
"google/gemma-2-9b-it:free.description": "Gemma 2 هي عائلة نماذج نصية مفتوحة المصدر وخفيفة الوزن من Google.",
|
||||
"google/gemma-2-9b.description": "Gemma 2 هي عائلة نماذج فعالة من Google تناسب التطبيقات الصغيرة ومعالجة البيانات المعقدة.",
|
||||
"google/gemma-2b-it.description": "Gemma Instruct (2B) يوفر معالجة أساسية للتعليمات للتطبيقات الخفيفة.",
|
||||
"google/gemma-3-12b-it.description": "Gemma 3 12B هو نموذج لغوي مفتوح المصدر من Google يحدد معيارًا جديدًا للكفاءة والأداء.",
|
||||
@@ -696,13 +664,13 @@
|
||||
"gpt-3.5-turbo.description": "GPT 3.5 Turbo لتوليد النصوص وفهمها؛ يشير حاليًا إلى gpt-3.5-turbo-0125.",
|
||||
"gpt-35-turbo-16k.description": "GPT-3.5 Turbo 16k هو نموذج توليد نصوص عالي السعة للمهام المعقدة.",
|
||||
"gpt-35-turbo.description": "GPT-3.5 Turbo هو النموذج الفعال من OpenAI للدردشة وتوليد النصوص، ويدعم استدعاء الوظائف المتوازية.",
|
||||
"gpt-4-0125-preview.description": "أحدث إصدار من GPT-4 Turbo يدعم الرؤية. الطلبات البصرية تدعم وضع JSON واستدعاء الوظائف. إنه نموذج متعدد الوسائط فعال من حيث التكلفة يوازن بين الدقة والكفاءة للتطبيقات في الوقت الحقيقي.",
|
||||
"gpt-4-0125-preview.description": "أحدث نموذج GPT-4 Turbo يتضمن الرؤية. يمكن استخدام طلبات الرؤية في وضع JSON واستدعاء الوظائف. GPT-4 Turbo هو إصدار محسن يوازن بين الدقة والكفاءة للمهام متعددة الوسائط والتفاعلات في الوقت الفعلي.",
|
||||
"gpt-4-0613.description": "يوفر GPT-4 نافذة سياق أكبر للتعامل مع مدخلات أطول، مما يجعله مناسبًا لتجميع المعلومات الواسعة وتحليل البيانات.",
|
||||
"gpt-4-1106-preview.description": "أحدث إصدار من GPT-4 Turbo يدعم الرؤية. الطلبات البصرية تدعم وضع JSON واستدعاء الوظائف. إنه نموذج متعدد الوسائط فعال من حيث التكلفة يوازن بين الدقة والكفاءة للتطبيقات في الوقت الحقيقي.",
|
||||
"gpt-4-1106-preview.description": "أحدث نموذج GPT-4 Turbo يتضمن الرؤية. يمكن استخدام طلبات الرؤية في وضع JSON واستدعاء الوظائف. GPT-4 Turbo هو إصدار محسن يوازن بين الدقة والكفاءة للمهام متعددة الوسائط والتفاعلات في الوقت الفعلي.",
|
||||
"gpt-4-32k-0613.description": "يوفر GPT-4 نافذة سياق أكبر للتعامل مع مدخلات أطول في السيناريوهات التي تتطلب دمج معلومات واسع وتحليل بيانات.",
|
||||
"gpt-4-32k.description": "يوفر GPT-4 نافذة سياق أكبر للتعامل مع مدخلات أطول في السيناريوهات التي تتطلب دمج معلومات واسع وتحليل بيانات.",
|
||||
"gpt-4-turbo-2024-04-09.description": "أحدث إصدار من GPT-4 Turbo يدعم الرؤية. الطلبات البصرية تدعم وضع JSON واستدعاء الوظائف. إنه نموذج متعدد الوسائط فعال من حيث التكلفة يوازن بين الدقة والكفاءة للتطبيقات في الوقت الحقيقي.",
|
||||
"gpt-4-turbo-preview.description": "أحدث إصدار من GPT-4 Turbo يدعم الرؤية. الطلبات البصرية تدعم وضع JSON واستدعاء الوظائف. إنه نموذج متعدد الوسائط فعال من حيث التكلفة يوازن بين الدقة والكفاءة للتطبيقات في الوقت الحقيقي.",
|
||||
"gpt-4-turbo-preview.description": "أحدث نموذج GPT-4 Turbo يتضمن الرؤية. يمكن استخدام طلبات الرؤية في وضع JSON واستدعاء الوظائف. GPT-4 Turbo هو إصدار محسن يوازن بين الدقة والكفاءة للمهام متعددة الوسائط والتفاعلات في الوقت الفعلي.",
|
||||
"gpt-4-turbo.description": "أحدث إصدار من GPT-4 Turbo يدعم الرؤية. الطلبات البصرية تدعم وضع JSON واستدعاء الوظائف. إنه نموذج متعدد الوسائط فعال من حيث التكلفة يوازن بين الدقة والكفاءة للتطبيقات في الوقت الحقيقي.",
|
||||
"gpt-4-vision-preview.description": "معاينة GPT-4 Vision، مصمم لمهام تحليل ومعالجة الصور.",
|
||||
"gpt-4.1-mini.description": "GPT-4.1 mini يوازن بين الذكاء والسرعة والتكلفة، مما يجعله جذابًا للعديد من الاستخدامات.",
|
||||
@@ -749,7 +717,7 @@
|
||||
"gpt-5.4-pro.description": "GPT-5.4 Pro من OpenAI — النموذج الأكثر قدرة مع أقصى سياق وتفكير.",
|
||||
"gpt-5.4.description": "GPT-5.4 من OpenAI — نموذج الجيل التالي مع نافذة سياق 1M+ وإدخال متعدد الوسائط.",
|
||||
"gpt-5.5-pro.description": "GPT-5.5 Pro يستخدم المزيد من الحوسبة للتفكير بشكل أعمق وتقديم إجابات أفضل باستمرار.",
|
||||
"gpt-5.5.description": "GPT-5.5 هو النموذج الرائد للعمل المهني الأكثر تعقيدًا، البرمجة، والمهام الوكيلية.",
|
||||
"gpt-5.5.description": "GPT-5.5 هو نموذجنا الأحدث للمهام المهنية الأكثر تعقيدًا.",
|
||||
"gpt-5.description": "GPT-5 من OpenAI — النموذج الرئيسي مع التفكير المتقدم والإدخال متعدد الوسائط.",
|
||||
"gpt-audio.description": "GPT Audio هو نموذج دردشة عام يدعم الإدخال والإخراج الصوتي، مدعوم في واجهة Chat Completions API.",
|
||||
"gpt-image-1-mini.description": "إصدار منخفض التكلفة من GPT Image 1 يدعم إدخال نصوص وصور وإخراج صور.",
|
||||
@@ -772,8 +740,11 @@
|
||||
"grok-4-fast-reasoning.description": "يسعدنا إطلاق Grok 4 Fast، أحدث تقدم في نماذج الاستدلال منخفضة التكلفة.",
|
||||
"grok-4.20-0309-non-reasoning.description": "نموذج غير تفكير للاستخدامات البسيطة.",
|
||||
"grok-4.20-0309-reasoning.description": "نموذج ذكي وسريع للغاية يفكر قبل الرد.",
|
||||
"grok-4.20-beta-0309-non-reasoning.description": "إصدار غير مفكر للاستخدامات البسيطة.",
|
||||
"grok-4.20-beta-0309-reasoning.description": "نموذج ذكي وسريع للغاية يفكر قبل الرد.",
|
||||
"grok-4.20-multi-agent-0309.description": "فريق من 4 أو 16 وكيلًا، يتفوق في حالات الاستخدام البحثية، لا يدعم حاليًا الأدوات على جانب العميل. يدعم فقط أدوات xAI على جانب الخادم (مثل X Search، أدوات البحث على الويب) وأدوات MCP البعيدة.",
|
||||
"grok-4.description": "أحدث نموذج رئيسي من Grok مع أداء لا مثيل له في اللغة، الرياضيات، والتفكير — نموذج شامل حقيقي. يشير حاليًا إلى grok-4-0709؛ بسبب الموارد المحدودة، هو مؤقتًا أعلى بنسبة 10% من التسعير الرسمي ومن المتوقع أن يعود إلى السعر الرسمي لاحقًا.",
|
||||
"grok-4.3.description": "أكثر نموذج لغة كبير يسعى للحقيقة في العالم.",
|
||||
"grok-4.description": "نموذجنا الرائد والأقوى، يتميز في معالجة اللغة الطبيعية، الرياضيات، والتفكير—مثالي لجميع الاستخدامات.",
|
||||
"grok-code-fast-1.description": "يسعدنا إطلاق grok-code-fast-1، نموذج استدلال سريع وفعال من حيث التكلفة يتفوق في البرمجة التلقائية.",
|
||||
"grok-imagine-image-pro.description": "إنشاء صور من مطالبات نصية، تحرير الصور الموجودة باستخدام اللغة الطبيعية، أو تحسين الصور بشكل تكراري من خلال محادثات متعددة الأدوار.",
|
||||
"grok-imagine-image.description": "إنشاء صور من مطالبات نصية، تحرير الصور الموجودة باستخدام اللغة الطبيعية، أو تحسين الصور بشكل تكراري من خلال محادثات متعددة الأدوار.",
|
||||
@@ -820,7 +791,6 @@
|
||||
"intern-s1-mini.description": "نموذج كبير متعدد الوسائط خفيف الوزن يتميز بقدرات استدلال علمية قوية.",
|
||||
"intern-s1-pro.description": "لقد أطلقنا نموذج الاستدلال متعدد الوسائط الأكثر تقدمًا مفتوح المصدر، حاليًا النموذج الكبير متعدد الوسائط مفتوح المصدر الأفضل أداءً من حيث الأداء العام.",
|
||||
"intern-s1.description": "نموذج الاستدلال متعدد الوسائط مفتوح المصدر لا يظهر فقط قدرات عامة قوية ولكنه يحقق أداءً متقدمًا عبر مجموعة واسعة من المهام العلمية.",
|
||||
"internlm/internlm2_5-7b-chat.description": "InternLM2.5-7B-Chat هو نموذج محادثة مفتوح المصدر مبني على بنية InternLM2. يركز نموذج 7B على توليد الحوارات ويدعم اللغتين الصينية والإنجليزية، ويستخدم تدريبًا حديثًا لتقديم محادثات ذكية وسلسة. مناسب لسيناريوهات متعددة مثل دعم العملاء والمساعدين الشخصيين.",
|
||||
"internvl2.5-38b-mpo.description": "InternVL2.5 38B MPO هو نموذج مدرب مسبقًا متعدد الوسائط للاستدلال المعقد بين الصور والنصوص.",
|
||||
"internvl3-14b.description": "InternVL3 14B هو نموذج متعدد الوسائط متوسط الحجم يوازن بين الأداء والتكلفة.",
|
||||
"internvl3-1b.description": "InternVL3 1B هو نموذج متعدد الوسائط خفيف الوزن مناسب للنشر في بيئات محدودة الموارد.",
|
||||
@@ -835,11 +805,10 @@
|
||||
"kimi-k2-0905-preview.description": "kimi-k2-0905-preview يوفر نافذة سياق 256k، برمجة وكيلة أقوى، جودة أفضل لرموز الواجهة الأمامية، وفهم سياقي محسن.",
|
||||
"kimi-k2-instruct.description": "Kimi K2 Instruct هو النموذج الرسمي للاستدلال من Kimi مع سياق طويل للبرمجة، الأسئلة والأجوبة، والمزيد.",
|
||||
"kimi-k2-thinking-turbo.description": "إصدار K2 عالي السرعة للتفكير الطويل مع نافذة سياق 256k، استدلال عميق قوي، وإخراج 60–100 رمز/ثانية.",
|
||||
"kimi-k2-thinking.description": "Kimi-K2 هو نموذج أساسي ببنية MoE أطلقته Moonshot AI بقدرات فائقة في البرمجة والوكلاء. يحتوي على إجمالي 1T من المعلمات و32B من المعلمات النشطة. في اختبارات الأداء المعيارية في الفئات الرئيسية مثل التفكير العام، والبرمجة، والرياضيات، والوكلاء، يتفوق أداء نموذج K2 على النماذج المفتوحة المصدر الرئيسية الأخرى.",
|
||||
"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.6.description": "Kimi K2.6 هو أحدث نموذج وأكثرها قدرة من Kimi، يقدم برمجة طويلة الأفق أقوى، اتباع التعليمات، والتصحيح الذاتي مع دعم النصوص، الصور، والفيديو بالإضافة إلى المهام الوكيلة والدردشة.",
|
||||
"kimi-k2.description": "Kimi-K2 هو نموذج MoE أساسي من Moonshot AI يتمتع بقدرات قوية في البرمجة والوكالة، بإجمالي 1 تريليون معلمة و32 مليار نشطة. يتفوق على النماذج المفتوحة السائدة في اختبارات الاستدلال العام، البرمجة، الرياضيات، ومهام الوكالة.",
|
||||
"kimi-k2.6.description": "Kimi-K2.6 هو نموذج لغة كبير تم إطلاقه بواسطة Moonshot AI، يتميز بقدرات ممتازة في البرمجة واستدعاء الأدوات. يتم دعم نشر الخدمة فقط في الصين القارية.",
|
||||
"kimi-k2:1t.description": "Kimi K2 هو نموذج LLM كبير من نوع MoE من Moonshot AI بإجمالي 1 تريليون معلمة و32 مليار نشطة لكل تمرير أمامي. مُحسّن لقدرات الوكالة بما في ذلك استخدام الأدوات المتقدمة، الاستدلال، وتوليد الشيفرة.",
|
||||
"kling/kling-v3-image-generation.description": "يدعم ما يصل إلى 10 صور مرجعية، مما يتيح لك تثبيت الموضوعات والعناصر ونغمات الألوان لضمان نمط متسق. يجمع بين نقل النمط، الإشارة إلى الصور الشخصية/الشخصيات، دمج الصور المتعددة، والتلوين المحلي للتحكم المرن. يقدم تفاصيل واقعية للصور الشخصية، مع مرئيات عامة دقيقة وغنية بالطبقات، تتميز بألوان وأجواء سينمائية.",
|
||||
"kling/kling-v3-omni-image-generation.description": "افتح مرئيات سرد القصص السينمائية مع توليد الصور الجديدة وإخراج مباشر بدقة 2K/4K. يحلل بعمق العناصر السمعية والبصرية في التعليمات لتنفيذ الإبداع بدقة. يدعم إدخالات مرجعية متعددة مرنة وترقيات جودة شاملة، مثالي للقصص المصورة، فن المفاهيم السردية، وتصميم المشاهد.",
|
||||
@@ -904,7 +873,6 @@
|
||||
"meta-llama/llama-3-8b-instruct.description": "Llama 3 8B Instruct مُحسّن للحوار عالي الجودة، ويتفوق على العديد من النماذج المغلقة.",
|
||||
"meta-llama/llama-3.1-70b-instruct.description": "أحدث سلسلة Llama 3.1 من Meta، النسخة المُعدّة للتعليمات بسعة 70 مليار معامل، مُحسّنة للحوار عالي الجودة. تُظهر أداءً قوياً في التقييمات الصناعية مقارنة بالنماذج المغلقة الرائدة. (متاحة فقط للجهات المعتمدة تجارياً.)",
|
||||
"meta-llama/llama-3.1-8b-instruct.description": "أحدث سلسلة Llama 3.1 من Meta، النسخة المُعدّة للتعليمات بسعة 8 مليارات معامل، سريعة وفعالة بشكل خاص. تُظهر أداءً قوياً في التقييمات الصناعية، متفوقة على العديد من النماذج المغلقة الرائدة. (متاحة فقط للجهات المعتمدة تجارياً.)",
|
||||
"meta-llama/llama-3.1-8b-instruct:free.description": "LLaMA 3.1 يدعم لغات متعددة ويُعد من النماذج الرائدة في التوليد.",
|
||||
"meta-llama/llama-3.2-11b-vision-instruct.description": "تم تصميم LLaMA 3.2 لمهام تجمع بين الرؤية والنص. يتفوق في توصيف الصور والأسئلة البصرية، ويجسر بين توليد اللغة والاستدلال البصري.",
|
||||
"meta-llama/llama-3.2-3b-instruct.description": "meta-llama/llama-3.2-3b-instruct",
|
||||
"meta-llama/llama-3.3-70b-instruct.description": "Llama 3.3 هو النموذج مفتوح المصدر الأكثر تقدماً من Llama متعدد اللغات، يقدم أداءً قريباً من 405B بتكلفة منخفضة جداً. يعتمد على Transformer وتم تحسينه باستخدام SFT وRLHF لتحقيق الفائدة والسلامة. النسخة المُعدّة للتعليمات مُحسّنة للدردشة متعددة اللغات وتتفوّق على العديد من النماذج المفتوحة والمغلقة في معايير الصناعة. تاريخ قطع المعرفة: ديسمبر 2023.",
|
||||
@@ -922,7 +890,6 @@
|
||||
"meta/Meta-Llama-3.1-405B-Instruct.description": "نموذج لاما 3.1 المضبوط على التعليمات، مُحسّن للدردشة متعددة اللغات، ويؤدي أداءً قويًا في معايير الصناعة بين النماذج المفتوحة والمغلقة.",
|
||||
"meta/Meta-Llama-3.1-70B-Instruct.description": "نموذج لاما 3.1 المضبوط على التعليمات، مُحسّن للدردشة متعددة اللغات، ويؤدي أداءً قويًا في معايير الصناعة بين النماذج المفتوحة والمغلقة.",
|
||||
"meta/Meta-Llama-3.1-8B-Instruct.description": "نموذج لاما 3.1 المضبوط على التعليمات، مُحسّن للدردشة متعددة اللغات، ويؤدي أداءً قويًا في معايير الصناعة بين النماذج المفتوحة والمغلقة.",
|
||||
"meta/llama-3.1-405b-instruct.description": "نموذج لغوي متقدم يدعم توليد البيانات الاصطناعية، وتقطير المعرفة، والاستدلال لمهام الدردشة والبرمجة والمجالات المتخصصة.",
|
||||
"meta/llama-3.1-70b-instruct.description": "مصمم للحوار المعقد مع فهم ممتاز للسياق، واستدلال، وتوليد نصوص.",
|
||||
"meta/llama-3.1-70b.description": "نسخة محدثة من لاما 3 70B Instruct من ميتا، تدعم سياقًا يصل إلى 128 ألف رمز، وتدعم لغات متعددة، مع تحسينات في الاستدلال.",
|
||||
"meta/llama-3.1-8b-instruct.description": "نموذج متطور يتمتع بفهم لغوي قوي، واستدلال، وتوليد نصوص.",
|
||||
@@ -962,7 +929,6 @@
|
||||
"minimax-m2.description": "MiniMax M2 هو نموذج لغوي كبير وفعّال صُمم خصيصًا للبرمجة وسير عمل الوكلاء.",
|
||||
"minimax/minimax-m2.1.description": "MiniMax-M2.1 هو نموذج لغوي كبير وخفيف الوزن ومتطور، مُحسّن للبرمجة وسير عمل الوكلاء وتطوير التطبيقات الحديثة، ويقدم مخرجات أنظف وأكثر إيجازًا واستجابة أسرع.",
|
||||
"minimax/minimax-m2.description": "MiniMax-M2 هو نموذج عالي القيمة يتميز في مهام البرمجة والوكلاء في العديد من سيناريوهات الهندسة.",
|
||||
"minimaxai/minimax-m2.5.description": "MiniMax-M2.5 هو أحدث نموذج لغة كبير من MiniMax، يتميز ببنية Mixture-of-Experts (MoE) مع إجمالي 229 مليار معلمة. يحقق أداءً رائدًا في الصناعة في البرمجة، استدعاء أدوات الوكيل، مهام البحث، وسيناريوهات المكتب.",
|
||||
"ministral-3:14b.description": "Ministral 3 14B هو أكبر نموذج في سلسلة Ministral 3، يقدم أداءً متقدمًا مماثلًا لنظيره الأكبر Mistral Small 3.2 24B. مُحسن للنشر المحلي، يقدم أداءً عاليًا على مختلف الأجهزة بما في ذلك الإعدادات المحلية.",
|
||||
"ministral-3:3b.description": "Ministral 3 3B هو أصغر وأكفأ نموذج في سلسلة Ministral 3، يقدم قدرات قوية في اللغة والرؤية في حزمة مدمجة. مصمم للنشر على الحافة، يقدم أداءً عاليًا على مختلف الأجهزة بما في ذلك الإعدادات المحلية.",
|
||||
"ministral-3:8b.description": "Ministral 3 8B هو نموذج قوي وفعال في سلسلة Ministral 3، يقدم قدرات نصية ورؤية من الدرجة الأولى. مُصمم للنشر على الحافة، يقدم أداءً عاليًا على مختلف الأجهزة بما في ذلك الإعدادات المحلية.",
|
||||
@@ -978,6 +944,7 @@
|
||||
"mistral-large-latest.description": "Mistral Large هو النموذج الرئيسي، يتفوق في المهام متعددة اللغات، التفكير المعقد، وتوليد الكود للتطبيقات المتقدمة.",
|
||||
"mistral-large.description": "Mixtral Large هو النموذج الرئيسي من Mistral، يجمع بين توليد الكود، والرياضيات، والاستدلال مع نافذة سياق 128K.",
|
||||
"mistral-medium-2508.description": "Mistral Medium 3.1 يقدم أداءً متقدمًا بتكلفة أقل بـ 8 مرات ويُبسط نشر المؤسسات.",
|
||||
"mistral-medium-3.5.description": "Mistral Medium 3.5 هو نموذج متعدد الوسائط من الدرجة الأولى تم تحسينه لحالات الاستخدام الوكالية والبرمجية، تم إصداره كأوزان مفتوحة بموجب ترخيص MIT المعدل.",
|
||||
"mistral-nemo-instruct.description": "Mistral-Nemo-Instruct-2407 هو الإصدار الموجه بالتعليمات من Mistral-Nemo-Base-2407.",
|
||||
"mistral-nemo.description": "Mistral Nemo هو نموذج فعال يحتوي على 12 مليار معامل من Mistral AI وNVIDIA.",
|
||||
"mistral-small-2506.description": "Mistral Small هو خيار اقتصادي وسريع وموثوق للترجمة، التلخيص، وتحليل المشاعر.",
|
||||
@@ -1020,7 +987,6 @@
|
||||
"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، مناسب للبرمجة عالية الجودة واستخدام الأدوات.",
|
||||
"moonshotai/kimi-k2-0905.description": "Kimi K2 0905 هو تحديث يعزز أداء السياق والتفكير مع تحسينات في البرمجة.",
|
||||
"moonshotai/kimi-k2-instruct-0905.description": "نموذج kimi-k2-0905-preview يدعم نافذة سياق بحجم 256K، مع برمجة وكيلة أقوى، وشيفرة أمامية أكثر صقلًا وعملية، وفهم أفضل للسياق.",
|
||||
"moonshotai/kimi-k2-thinking-turbo.description": "Kimi K2 Thinking Turbo هو إصدار عالي السرعة من Kimi K2 Thinking، يقلل بشكل كبير من زمن الاستجابة مع الحفاظ على عمق التفكير.",
|
||||
"moonshotai/kimi-k2-thinking.description": "Kimi K2 Thinking هو نموذج التفكير من Moonshot، مُحسّن لمهام التفكير العميق، مع قدرات عامة كوكلاء.",
|
||||
"moonshotai/kimi-k2.5.description": "Kimi K2.5 هو النموذج الأكثر ذكاءً من Kimi حتى الآن، يتميز بهندسة متعددة الوسائط أصلية.",
|
||||
@@ -1079,7 +1045,7 @@
|
||||
"openai/gpt-5.description": "GPT-5 هو نموذج عالي الأداء من OpenAI لمجموعة واسعة من المهام الإنتاجية والبحثية.",
|
||||
"openai/gpt-oss-120b.description": "نموذج لغة كبير عام القدرات يتمتع بتفكير قوي وقابل للتحكم.",
|
||||
"openai/gpt-oss-20b.description": "نموذج لغة صغير الحجم بوزن مفتوح، محسّن لزمن استجابة منخفض وبيئات محدودة الموارد، بما في ذلك النشر المحلي وعلى الأطراف.",
|
||||
"openai/o1-mini.description": "o1-mini هو نموذج تفكير سريع وفعال من حيث التكلفة مصمم للبرمجة والرياضيات والعلوم. يدعم سياق 128K وتاريخ معرفة حتى أكتوبر 2023.",
|
||||
"openai/o1-mini.description": "o1-mini هو نموذج تفكير سريع وفعال من حيث التكلفة مصمم لحالات استخدام البرمجة، الرياضيات، والعلوم. لديه سياق 128K وقطع معرفة في أكتوبر 2023.",
|
||||
"openai/o1-preview.description": "o1 هو نموذج التفكير الجديد من OpenAI للمهام المعقدة التي تتطلب معرفة واسعة. يدعم سياق 128K وتاريخ معرفة حتى أكتوبر 2023.",
|
||||
"openai/o1.description": "OpenAI o1 هو نموذج تفكير رائد مصمم لحل المشكلات المعقدة التي تتطلب تفكيرًا عميقًا، ويقدم تفكيرًا قويًا ودقة أعلى في المهام متعددة الخطوات.",
|
||||
"openai/o3-mini-high.description": "o3-mini (تفكير عالي) يقدم ذكاءً أعلى بنفس تكلفة وزمن استجابة o1-mini.",
|
||||
@@ -1123,7 +1089,6 @@
|
||||
"qianfan-check-vl.description": "Qianfan Check VL هو نموذج مراجعة محتوى متعدد الوسائط لمهام التوافق والتعرف على الصور والنصوص.",
|
||||
"qianfan-composition.description": "Qianfan Composition هو نموذج إنشاء متعدد الوسائط لفهم وتوليد الصور والنصوص المختلطة.",
|
||||
"qianfan-engcard-vl.description": "Qianfan EngCard VL هو نموذج تعرف متعدد الوسائط يركز على السيناريوهات الإنجليزية.",
|
||||
"qianfan-llama-vl-8b.description": "Qianfan Llama VL 8B هو نموذج متعدد الوسائط مبني على Llama لفهم عام للصور والنصوص.",
|
||||
"qianfan-multipicocr.description": "Qianfan MultiPicOCR هو نموذج OCR متعدد الصور لاكتشاف النصوص والتعرف عليها عبر الصور.",
|
||||
"qianfan-qi-vl.description": "Qianfan QI VL هو نموذج سؤال وجواب متعدد الوسائط للاسترجاع الدقيق والإجابة في سيناريوهات الصور والنصوص المعقدة.",
|
||||
"qianfan-singlepicocr.description": "Qianfan SinglePicOCR هو نموذج OCR لصورة واحدة بدقة عالية في التعرف على الأحرف.",
|
||||
@@ -1162,7 +1127,6 @@
|
||||
"qwen-vl-plus.description": "نموذج Qwen المحسن للغة والرؤية على نطاق واسع مع تحسينات كبيرة في التفاصيل والتعرف على النصوص، يدعم دقة تتجاوز الميجابيكسل ونسب أبعاد عشوائية.",
|
||||
"qwen-vl-v1.description": "نموذج مدرب مسبقًا مستند إلى Qwen-7B مع وحدة رؤية مضافة ودقة إدخال صور 448.",
|
||||
"qwen/qwen-2-7b-instruct.description": "Qwen2 هي سلسلة نماذج اللغة الكبيرة الجديدة من Qwen. Qwen2 7B هو نموذج قائم على المحولات يتميز بفهم لغوي قوي، وقدرات متعددة اللغات، والبرمجة، والرياضيات، والاستدلال.",
|
||||
"qwen/qwen-2-7b-instruct:free.description": "Qwen2 هي عائلة جديدة من نماذج اللغة الكبيرة تتميز بفهم وتوليد أقوى.",
|
||||
"qwen/qwen-2-vl-72b-instruct.description": "Qwen2-VL هو أحدث إصدار من Qwen-VL، يحقق أداءً رائدًا في معايير الرؤية مثل MathVista وDocVQA وRealWorldQA وMTVQA. يمكنه فهم أكثر من 20 دقيقة من الفيديو للإجابة على الأسئلة، الحوار، وإنشاء المحتوى بجودة عالية. كما يتعامل مع الاستدلال المعقد واتخاذ القرار، ويتكامل مع الأجهزة المحمولة والروبوتات للتصرف بناءً على السياق البصري والتعليمات النصية. بالإضافة إلى الإنجليزية والصينية، يقرأ النصوص في الصور بلغات متعددة، منها معظم اللغات الأوروبية، اليابانية، الكورية، العربية، والفيتنامية.",
|
||||
"qwen/qwen-2.5-72b-instruct.description": "Qwen2.5-72B-Instruct هو أحد أحدث إصدارات نماذج اللغة الكبيرة من Alibaba Cloud. يقدم هذا النموذج تحسينات ملحوظة في البرمجة والرياضيات، ويدعم أكثر من 29 لغة (بما في ذلك الصينية والإنجليزية)، ويعزز بشكل كبير اتباع التعليمات، وفهم البيانات المنظمة، والإخراج المنظم (خاصة JSON).",
|
||||
"qwen/qwen2.5-32b-instruct.description": "Qwen2.5-32B-Instruct هو أحد أحدث إصدارات نماذج اللغة الكبيرة من Alibaba Cloud. يقدم هذا النموذج تحسينات ملحوظة في البرمجة والرياضيات، ويدعم أكثر من 29 لغة (بما في ذلك الصينية والإنجليزية)، ويعزز بشكل كبير اتباع التعليمات، وفهم البيانات المنظمة، والإخراج المنظم (خاصة JSON).",
|
||||
@@ -1170,16 +1134,11 @@
|
||||
"qwen/qwen2.5-coder-32b-instruct.description": "نموذج متقدم لتوليد الشيفرة، الاستدلال، والإصلاح عبر لغات البرمجة الشائعة.",
|
||||
"qwen/qwen2.5-coder-7b-instruct.description": "نموذج برمجة متوسط الحجم قوي مع سياق 32K، يتميز بالبرمجة متعددة اللغات.",
|
||||
"qwen/qwen3-14b.description": "Qwen3-14B هو إصدار 14B مخصص للاستدلال العام وسيناريوهات الدردشة.",
|
||||
"qwen/qwen3-14b:free.description": "Qwen3-14B هو نموذج سببي كثيف يحتوي على 14.8 مليار معلمة، مصمم للاستدلال المعقد والدردشة الفعالة. يتنقل بين وضع التفكير للرياضيات، البرمجة، والمنطق، ووضع غير التفكير للدردشة العامة. تم تحسينه لاتباع التعليمات، استخدام أدوات الوكلاء، والكتابة الإبداعية بأكثر من 100 لغة ولهجة. يدعم سياق 32K أصليًا ويتوسع إلى 131K باستخدام YaRN.",
|
||||
"qwen/qwen3-235b-a22b-2507.description": "Qwen3-235B-A22B-Instruct-2507 هو إصدار Instruct من سلسلة Qwen3، يوازن بين استخدام التعليمات متعددة اللغات وسيناريوهات السياق الطويل.",
|
||||
"qwen/qwen3-235b-a22b-thinking-2507.description": "Qwen3-235B-A22B-Thinking-2507 هو إصدار التفكير من Qwen3، معزز للمهام المعقدة في الرياضيات والاستدلال.",
|
||||
"qwen/qwen3-235b-a22b.description": "Qwen3-235B-A22B هو نموذج MoE يحتوي على 235 مليار معامل من Qwen، مع 22 مليار نشطة في كل تمرير. يتنقل بين وضع التفكير للمهام المعقدة في الرياضيات والبرمجة، ووضع غير التفكير للدردشة الفعالة. يتميز باستدلال قوي، ودعم متعدد اللغات (أكثر من 100 لغة ولهجة)، واتباع تعليمات متقدم، واستخدام أدوات الوكلاء. يدعم سياقًا أصليًا حتى 32K ويتوسع إلى 131K باستخدام YaRN.",
|
||||
"qwen/qwen3-235b-a22b:free.description": "Qwen3-235B-A22B هو نموذج MoE يحتوي على 235 مليار معامل من Qwen، مع 22 مليار نشطة في كل تمرير. يتنقل بين وضع التفكير للمهام المعقدة في الرياضيات والبرمجة، ووضع غير التفكير للدردشة الفعالة. يتميز باستدلال قوي، ودعم متعدد اللغات (أكثر من 100 لغة ولهجة)، واتباع تعليمات متقدم، واستخدام أدوات الوكلاء. يدعم سياقًا أصليًا حتى 32K ويتوسع إلى 131K باستخدام YaRN.",
|
||||
"qwen/qwen3-30b-a3b.description": "Qwen3 هو الجيل الأحدث من نماذج Qwen LLM، يتميز ببنى كثيفة وMoE، ويتفوق في الاستدلال، دعم اللغات المتعددة، ومهام الوكلاء المتقدمة. يتميز بقدرته الفريدة على التبديل بين نمط التفكير للاستدلال المعقد ونمط غير التفكير للدردشة الفعالة، مما يضمن أداءً عالي الجودة ومتعدد الاستخدامات.\n\nيتفوق Qwen3 بشكل كبير على النماذج السابقة مثل QwQ وQwen2.5، ويقدم أداءً ممتازًا في الرياضيات، البرمجة، الاستدلال المنطقي، الكتابة الإبداعية، والدردشة التفاعلية. يحتوي إصدار Qwen3-30B-A3B على 30.5 مليار معلمة (3.3 مليار نشطة)، 48 طبقة، 128 خبيرًا (8 نشطين لكل مهمة)، ويدعم سياقًا يصل إلى 131 ألف باستخدام YaRN، مما يضع معيارًا جديدًا للنماذج المفتوحة.",
|
||||
"qwen/qwen3-30b-a3b:free.description": "Qwen3 هو الجيل الأحدث من نماذج Qwen LLM، يتميز ببنى كثيفة وMoE، ويتفوق في الاستدلال، دعم اللغات المتعددة، ومهام الوكلاء المتقدمة. يتميز بقدرته الفريدة على التبديل بين نمط التفكير للاستدلال المعقد ونمط غير التفكير للدردشة الفعالة، مما يضمن أداءً عالي الجودة ومتعدد الاستخدامات.\n\nيتفوق Qwen3 بشكل كبير على النماذج السابقة مثل QwQ وQwen2.5، ويقدم أداءً ممتازًا في الرياضيات، البرمجة، الاستدلال المنطقي، الكتابة الإبداعية، والدردشة التفاعلية. يحتوي إصدار Qwen3-30B-A3B على 30.5 مليار معلمة (3.3 مليار نشطة)، 48 طبقة، 128 خبيرًا (8 نشطين لكل مهمة)، ويدعم سياقًا يصل إلى 131 ألف باستخدام YaRN، مما يضع معيارًا جديدًا للنماذج المفتوحة.",
|
||||
"qwen/qwen3-32b.description": "Qwen3-32B هو نموذج LLM كثيف يحتوي على 32.8 مليار معلمة، مُحسَّن للاستدلال المعقد والدردشة الفعالة. يمكنه التبديل بين نمط التفكير للرياضيات والبرمجة والمنطق، ونمط غير التفكير للدردشة العامة السريعة. يتميز بأداء قوي في اتباع التعليمات، استخدام أدوات الوكلاء، والكتابة الإبداعية بأكثر من 100 لغة ولهجة. يدعم سياقًا أصليًا حتى 32 ألف ويتوسع إلى 131 ألف باستخدام YaRN.",
|
||||
"qwen/qwen3-32b:free.description": "Qwen3-32B هو نموذج LLM كثيف يحتوي على 32.8 مليار معلمة، مُحسَّن للاستدلال المعقد والدردشة الفعالة. يمكنه التبديل بين نمط التفكير للرياضيات والبرمجة والمنطق، ونمط غير التفكير للدردشة العامة السريعة. يتميز بأداء قوي في اتباع التعليمات، استخدام أدوات الوكلاء، والكتابة الإبداعية بأكثر من 100 لغة ولهجة. يدعم سياقًا أصليًا حتى 32 ألف ويتوسع إلى 131 ألف باستخدام YaRN.",
|
||||
"qwen/qwen3-8b:free.description": "Qwen3-8B هو نموذج LLM كثيف يحتوي على 8.2 مليار معلمة، مصمم للمهام التي تتطلب استدلالًا عاليًا ودردشة فعالة. يمكنه التبديل بين نمط التفكير للرياضيات والبرمجة والمنطق، ونمط غير التفكير للدردشة العامة. تم تحسينه لاتباع التعليمات، تكامل الوكلاء، والكتابة الإبداعية بأكثر من 100 لغة ولهجة. يدعم سياقًا أصليًا حتى 32 ألف ويتوسع إلى 131 ألف باستخدام YaRN.",
|
||||
"qwen/qwen3-coder-plus.description": "Qwen3-Coder-Plus هو نموذج ترميز من سلسلة Qwen، مُحسَّن لاستخدام الأدوات المعقدة وجلسات العمل الطويلة.",
|
||||
"qwen/qwen3-coder.description": "Qwen3-Coder هو نموذج من عائلة Qwen3 لتوليد الشيفرات، يتميز بفهم وتوليد الشيفرات في المستندات الطويلة.",
|
||||
"qwen/qwen3-max-preview.description": "Qwen3 Max (نسخة تجريبية) هو إصدار Max المتقدم في الاستدلال ودمج الأدوات.",
|
||||
@@ -1195,7 +1154,7 @@
|
||||
"qwen2.5-14b-instruct.description": "Qwen2.5 نموذج مفتوح المصدر بسعة 14 مليار معلمة.",
|
||||
"qwen2.5-32b-instruct.description": "Qwen2.5 نموذج مفتوح المصدر بسعة 32 مليار معلمة.",
|
||||
"qwen2.5-72b-instruct.description": "Qwen2.5 نموذج مفتوح المصدر بسعة 72 مليار معلمة.",
|
||||
"qwen2.5-7b-instruct.description": "Qwen2.5 7B Instruct هو نموذج مفتوح المصدر ناضج للدردشة وتوليد المحتوى في سيناريوهات متعددة.",
|
||||
"qwen2.5-7b-instruct.description": "Qwen2.5 نموذج مفتوح المصدر بحجم 7B.",
|
||||
"qwen2.5-coder-1.5b-instruct.description": "نموذج Qwen للبرمجة مفتوح المصدر.",
|
||||
"qwen2.5-coder-14b-instruct.description": "نموذج Qwen للبرمجة مفتوح المصدر.",
|
||||
"qwen2.5-coder-32b-instruct.description": "نموذج Qwen للبرمجة مفتوح المصدر.",
|
||||
@@ -1208,7 +1167,7 @@
|
||||
"qwen2.5-omni-7b.description": "نماذج Qwen-Omni تدعم المدخلات متعددة الوسائط (فيديو، صوت، صور، نص) وتنتج مخرجات صوتية ونصية.",
|
||||
"qwen2.5-vl-32b-instruct.description": "Qwen2.5 VL 32B Instruct هو نموذج متعدد الوسائط مفتوح المصدر مناسب للنشر الخاص والاستخدام في سيناريوهات متعددة.",
|
||||
"qwen2.5-vl-72b-instruct.description": "تحسين في اتباع التعليمات، والرياضيات، وحل المشكلات، والبرمجة، مع قدرة أقوى على التعرف على الكائنات. يدعم تحديد العناصر البصرية بدقة عبر التنسيقات، وفهم الفيديو الطويل (حتى 10 دقائق) مع توقيت الأحداث على مستوى الثانية، وترتيبها الزمني وفهم السرعة، ووكلاء يمكنهم التحكم في أنظمة التشغيل أو الهواتف المحمولة من خلال التحليل والتحديد. يتميز باستخراج المعلومات الأساسية بدقة وإخراج JSON. هذا هو الإصدار الأقوى بسعة 72B.",
|
||||
"qwen2.5-vl-7b-instruct.description": "Qwen2.5 VL 7B Instruct هو نموذج متعدد الوسائط خفيف الوزن يوازن بين تكلفة النشر وقدرة التعرف.",
|
||||
"qwen2.5-vl-7b-instruct.description": "تحسين اتباع التعليمات، الرياضيات، حل المشكلات، والبرمجة، مع قدرة أقوى على التعرف على الكائنات العامة. يدعم تحديد المواقع الدقيقة للعناصر البصرية عبر التنسيقات، فهم الفيديو الطويل (حتى 10 دقائق) مع توقيت الأحداث على مستوى الثانية، ترتيب زمني وفهم السرعة، ووكلاء يمكنهم التحكم في نظام التشغيل أو الهاتف المحمول عبر التحليل والتحديد. استخراج معلومات رئيسية قوي وإخراج JSON. هذا هو الإصدار الأقوى في السلسلة بحجم 72B.",
|
||||
"qwen2.5-vl-instruct.description": "Qwen2.5-VL هو أحدث نموذج رؤية-لغة في عائلة Qwen.",
|
||||
"qwen2.5.description": "Qwen2.5 هو الجيل الجديد من النماذج اللغوية الكبيرة من Alibaba، يتميز بأداء قوي في استخدامات متنوعة.",
|
||||
"qwen2.5:0.5b.description": "Qwen2.5 هو الجيل الجديد من النماذج اللغوية الكبيرة من Alibaba، يتميز بأداء قوي في استخدامات متنوعة.",
|
||||
@@ -1262,7 +1221,7 @@
|
||||
"qwen3.5-plus-2026-04-20.description": "Qwen 3.5 هو نموذج رؤية-لغة Plus أصلي. مقارنة بلقطة فبراير 15، يقدم هذا الإصدار تحسينات كبيرة في قدرات البرمجة الوكيلة وسرعة الاستدلال بشكل ملحوظ. تظل معرفته، تفكيره، وقدراته على السياق الطويل على مستوى عالٍ، مما يلبي متطلبات المهام الوكيلة المعقدة. يناسب البرمجة الوكيلة، سير العمل الإنتاجي، والسيناريوهات ذات الإنتاجية العالية. يتوافق هذا الإصدار مع لقطة أبريل 20، 2026.",
|
||||
"qwen3.5-plus.description": "Qwen3.5 Plus يدعم إدخال النصوص، الصور، والفيديو. أداؤه في المهام النصية البحتة يعادل Qwen3 Max، مع أداء أفضل وتكلفة أقل. قدراته متعددة الوسائط محسنة بشكل كبير مقارنة بسلسلة Qwen3 VL.",
|
||||
"qwen3.5:397b.description": "Qwen3.5 هو نموذج أساسي موحد للرؤية واللغة مع بنية هجينة (Mixture-of-Experts + انتباه خطي)، يقدم قدرات قوية في التفكير متعدد الوسائط، البرمجة، والسياقات الطويلة مع نافذة سياق 256K.",
|
||||
"qwen3.6-27b.description": "سلسلة Qwen 3.6 27B هي نموذج رؤية-لغة كثيف أصلي. مقارنة بالإصدار 3.5-27B، يقدم تحسينات كبيرة في قدرات البرمجة الوكيلة، مع تحسينات إضافية في الأداء STEM وقدرة التفكير. على الجانب البصري، يظهر مكاسب ملحوظة في الذكاء المكاني، تحديد المواقع، والكشف، بينما يتحسن أيضًا بشكل ثابت في فهم الفيديو، OCR الوثائق، وقدرات الوكيل البصري.",
|
||||
"qwen3.6-27b.description": "Qwen3.6 27B هو نموذج كثيف مفتوح المصدر يتميز بأداء قوي في التفكير، البرمجة، والقدرات العامة. يدعم وضع التفكير افتراضيًا، مما يوفر أداءً متوازنًا وكفاءة.",
|
||||
"qwen3.6-35b-a3b.description": "يعتمد نموذج Qwen3.6 35B-A3B للرؤية واللغة على بنية هجينة تدمج آلية الانتباه الخطي مع تصميم الخبراء المتعددين (MoE) المتناثر، مما يحقق كفاءة أعلى في الاستدلال. مقارنةً بنموذج 3.5-35B-A3B، يقدم هذا الإصدار تحسينات كبيرة في قدرات البرمجة الوكيلية، والاستدلال الرياضي، واستدلال الأكواد، والذكاء المكاني، إضافة إلى تحديد المواقع واكتشاف الأهداف.",
|
||||
"qwen3.6-flash.description": "يقدم نموذج Qwen3.6 Flash للرؤية واللغة أداءً محسّناً بشكل ملحوظ مقارنةً بإصدار 3.5-Flash. يركز النموذج على تعزيز قدرات البرمجة الوكيلية (متفوقاً بشكل كبير على سابقه في العديد من معايير تقييم الوكلاء البرمجيين)، إضافة إلى تحسين قدرات الاستدلال الرياضي واستدلال الأكواد. وعلى جانب الرؤية، يقدم النموذج تحسينات واضحة في الذكاء المكاني، مع تقدم قوي في تحديد المواقع واكتشاف الأهداف.",
|
||||
"qwen3.6-max-preview.description": "أكبر نموذج مغلق المصدر ضمن سلسلة Qwen3.6. يقدم معرفة أعمق بالعالم، وقدرة أعلى على اتباع التعليمات، وأداءً أقوى في البرمجة الوكيلية للمهام المعقدة. وهو نصي فقط، ويدعم وضع التفكير بشكل افتراضي، إضافة إلى التخزين المؤقت الصريح واستدعاء الدوال.",
|
||||
@@ -1274,6 +1233,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 يتميز بتوليد معزز بالاسترجاع من الويب للحصول على معلومات في الوقت الفعلي، تحسين تفسير التعليمات المعقدة، وتحسين اتساق المرجع لإنشاء مرئيات احترافية.",
|
||||
"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 مع دعم لغات موسع وسياق أطول.",
|
||||
@@ -1308,6 +1269,7 @@
|
||||
"step-3.5-flash-2603.description": "مبني على Step 3.5 Flash ومحسن لسيناريوهات الوكلاء عالية التردد، يحسن كفاءة الرموز وسرعة الاستدلال مع الحفاظ على قدرات التفكير واستدعاء الأدوات على مستوى النموذج الرئيسي. يدعم أيضًا التبديل إلى وضع التفكير المنخفض لتقليل استهلاك الموارد. بالإضافة إلى ذلك، تم إجراء تحسينات مستهدفة لتعزيز التوافق مع مهام البرمجة وإطارات العمل الوكيلة.",
|
||||
"step-3.5-flash.description": "نموذج التفكير اللغوي الرائد من Stepfun. يتميز بقدرات تفكير من الدرجة الأولى وقدرات تنفيذ سريعة وموثوقة. قادر على تحليل وتخطيط المهام المعقدة، واستدعاء الأدوات بسرعة وموثوقية لأداء المهام، والتعامل مع مختلف المهام المعقدة مثل التفكير المنطقي، الرياضيات، هندسة البرمجيات، والبحث المتعمق.",
|
||||
"step-3.description": "يتمتع هذا النموذج بإدراك بصري قوي واستدلال معقد، ويتعامل بدقة مع فهم المعرفة عبر المجالات، وتحليل الرياضيات والرؤية، ومجموعة واسعة من مهام التحليل البصري اليومية.",
|
||||
"step-image-edit-2.description": "نموذج تحرير خفيف الوزن من أحدث إصدار لـ Stepfun يدعم تحويل النص إلى صورة وتحرير الصور ضمن نموذج واحد. على الرغم من احتوائه على أقل من 6 مليارات معلمة، فإنه يحقق أداءً رائدًا على مستوى حجمه، ينافس النماذج مفتوحة المصدر في نطاق 12B–20B عبر المستويات. تستغرق كل مهمة تحرير فقط 1–2 ثانية، مما يعيد تعريف تجربة تحرير الصور التفاعلي في الوقت الفعلي.",
|
||||
"step-r1-v-mini.description": "نموذج استدلال يتمتع بفهم قوي للصور، يمكنه معالجة الصور والنصوص، ثم توليد نص بعد استدلال عميق. يتفوق في الاستدلال البصري ويقدم أداءً رائدًا في الرياضيات والبرمجة والاستدلال النصي، مع نافذة سياق تصل إلى 100 ألف.",
|
||||
"stepfun-ai/step3.description": "Step3 هو نموذج استدلال متعدد الوسائط متقدم من StepFun، يعتمد على بنية MoE مع 321 مليار معلمة إجمالية و38 مليار معلمة نشطة. تصميمه الشامل يقلل من تكلفة فك التشفير مع تقديم استدلال رؤية-لغة من الدرجة الأولى. مع تصميم MFA وAFD، يظل فعالًا على كل من المسرعات الرائدة والمنخفضة. يستخدم التدريب المسبق أكثر من 20 تريليون رمز نصي و4 تريليون رمز نصي-صوري عبر العديد من اللغات. يحقق أداءً رائدًا للنماذج المفتوحة في الرياضيات، البرمجة، ومعايير متعددة الوسائط.",
|
||||
"taichu4_vl_2b_nothinking.description": "الإصدار بدون التفكير من نموذج Taichu4.0-VL 2B يتميز باستخدام ذاكرة أقل، تصميم خفيف الوزن، سرعة استجابة سريعة، وقدرات فهم متعددة الوسائط قوية.",
|
||||
@@ -1323,11 +1285,7 @@
|
||||
"text-embedding-3-large.description": "أقوى نموذج تضمين للمهام باللغة الإنجليزية وغير الإنجليزية.",
|
||||
"text-embedding-3-small.description": "نموذج تضمين من الجيل التالي فعال من حيث التكلفة ومناسب للاسترجاع وسيناريوهات RAG.",
|
||||
"thudm/glm-4-32b.description": "GLM-4-32B-0414 هو نموذج ثنائي اللغة (صيني/إنجليزي) بسعة 32B وأوزان مفتوحة، مُحسَّن لتوليد الشيفرات، واستدعاء الوظائف، ومهام الوكلاء. تم تدريبه مسبقًا على 15 تريليون رمز عالي الجودة ومليء بالاستدلال، وتم تحسينه بموازنة تفضيلات البشر، وأخذ العينات بالرفض، والتعلم المعزز. يتفوق في الاستدلال المعقد، وتوليد المخرجات المنظمة، ويصل إلى مستوى أداء GPT-4o وDeepSeek-V3-0324 في العديد من المعايير.",
|
||||
"thudm/glm-4-32b:free.description": "GLM-4-32B-0414 هو نموذج ثنائي اللغة (صيني/إنجليزي) بسعة 32B وأوزان مفتوحة، مُحسَّن لتوليد الشيفرات، واستدعاء الوظائف، ومهام الوكلاء. تم تدريبه مسبقًا على 15 تريليون رمز عالي الجودة ومليء بالاستدلال، وتم تحسينه بموازنة تفضيلات البشر، وأخذ العينات بالرفض، والتعلم المعزز. يتفوق في الاستدلال المعقد، وتوليد المخرجات المنظمة، ويصل إلى مستوى أداء GPT-4o وDeepSeek-V3-0324 في العديد من المعايير.",
|
||||
"thudm/glm-4-9b-chat.description": "الإصدار مفتوح المصدر من نموذج GLM-4 الأحدث من Zhipu AI.",
|
||||
"thudm/glm-z1-32b.description": "GLM-Z1-32B-0414 هو إصدار استدلال محسَّن من GLM-4-32B، مصمم لحل المشكلات المعقدة في الرياضيات والمنطق والبرمجة. يستخدم تعلمًا معززًا موسعًا (تفضيلات زوجية خاصة بالمهمة وعامة) لتحسين المهام متعددة الخطوات. مقارنة بـ GLM-4-32B، يقدم Z1 تحسينات كبيرة في الاستدلال المنظم والقدرات في المجالات الرسمية. يدعم فرض خطوات التفكير من خلال هندسة التعليمات، وتحسين التماسك في المخرجات الطويلة، ومُحسَّن لسير عمل الوكلاء مع سياق طويل (عبر YaRN)، واستدعاء أدوات JSON، وأخذ عينات دقيقة لاستدلال مستقر. مثالي للحالات التي تتطلب اشتقاقات متعددة الخطوات أو رسمية دقيقة.",
|
||||
"thudm/glm-z1-rumination-32b.description": "GLM Z1 Rumination 32B هو نموذج تفكير عميق بسعة 32 مليار في سلسلة GLM-4-Z1، مُحسّن للمهام المعقدة المفتوحة التي تتطلب تفكيرًا طويل الأمد. مبني على glm-4-32b-0414، ويضيف مراحل تعزيز التعلم (RL) إضافية ومحاذاة متعددة المراحل، مما يقدّم قدرة \"التأمل\" التي تحاكي المعالجة المعرفية الممتدة. يشمل ذلك التفكير التكراري، والتحليل متعدد الخطوات، وسير العمل المدعوم بالأدوات مثل البحث، والاسترجاع، والتوليف المدرك للاستشهادات.\n\nيتفوّق في كتابة الأبحاث، والتحليل المقارن، والأسئلة المعقدة. يدعم استدعاء الوظائف لأساسيات البحث/التنقل (`search`، `click`، `open`، `finish`) في خطوط أنابيب الوكلاء. يتم التحكم في سلوك التأمل من خلال حلقات متعددة الجولات مع تشكيل مكافآت قائم على القواعد وآليات اتخاذ القرار المؤجل، وتمت معايرته مقابل أطر البحث العميق مثل نظام المحاذاة الداخلي لـ OpenAI. هذا الإصدار يركّز على العمق بدلاً من السرعة.",
|
||||
"tngtech/deepseek-r1t-chimera:free.description": "تم إنشاء DeepSeek-R1T-Chimera من خلال دمج DeepSeek-R1 و DeepSeek-V3 (0324)، حيث يجمع بين قدرات التفكير في R1 وكفاءة الرموز في V3. يعتمد على محول DeepSeek-MoE وتم تحسينه لتوليد النصوص العامة.\n\nيُدمج الأوزان المدربة مسبقًا لتحقيق توازن بين التفكير والكفاءة واتباع التعليمات. تم إصداره بموجب ترخيص MIT للاستخدام البحثي والتجاري.",
|
||||
"togethercomputer/StripedHyena-Nous-7B.description": "يوفّر StripedHyena Nous (7B) كفاءة حوسبة محسّنة من خلال بنيته واستراتيجيته.",
|
||||
"tts-1-hd.description": "أحدث نموذج تحويل النص إلى كلام، مُحسّن للجودة.",
|
||||
"tts-1.description": "أحدث نموذج تحويل النص إلى كلام، مُحسّن للسرعة في الوقت الحقيقي.",
|
||||
|
||||
@@ -58,24 +58,7 @@
|
||||
"agent.welcome.sentence.1": "سررت بلقائك! دعنا نتعرّف على بعض.",
|
||||
"agent.welcome.sentence.2": "ما نوع الشريك الذي تريدني أن أكونه؟",
|
||||
"agent.welcome.sentence.3": "أولًا، اختر لي اسمًا :)",
|
||||
"agent.welcome.suggestion.items.1.name": "لومي",
|
||||
"agent.welcome.suggestion.items.1.prompt": "لنسمّك لومي أولًا. دافئ، متفكّر، وقليل الخيال.",
|
||||
"agent.welcome.suggestion.items.2.name": "أطلس",
|
||||
"agent.welcome.suggestion.items.2.prompt": "ما رأيك في أطلس؟ ثابت، موثوق، وماهر في إنجاز المهام.",
|
||||
"agent.welcome.suggestion.items.3.name": "مومو",
|
||||
"agent.welcome.suggestion.items.3.prompt": "ربما مومو. خفيف الظل، لطيف، وسهل التحدّث معه.",
|
||||
"agent.welcome.suggestion.items.4.name": "نوفا",
|
||||
"agent.welcome.suggestion.items.4.prompt": "لنختر نوفا. حادّ، خيالي، ومليء بالأفكار الجديدة.",
|
||||
"agent.welcome.suggestion.items.5.name": "ميلو",
|
||||
"agent.welcome.suggestion.items.5.prompt": "ميلو يبدو جيدًا. ودود، سريع البديهة، وفعّال بهدوء.",
|
||||
"agent.welcome.suggestion.items.6.name": "أستر",
|
||||
"agent.welcome.suggestion.items.6.prompt": "ما رأيك في أستر؟ واضح، مباشر، وهادئ تحت الضغط.",
|
||||
"agent.welcome.suggestion.items.7.name": "بيكسل",
|
||||
"agent.welcome.suggestion.items.7.prompt": "تريد أن نسمّيك بيكسل؟ فضولي، مهتمّ بالمنتجات، ودقيق الملاحظة.",
|
||||
"agent.welcome.suggestion.items.8.name": "إيكو",
|
||||
"agent.welcome.suggestion.items.8.prompt": "ربما إيكو. صبور، منصت، ودائم الاهتمام بالتفاصيل.",
|
||||
"agent.welcome.suggestion.items.9.name": "أوربيت",
|
||||
"agent.welcome.suggestion.items.9.prompt": "لنجرّب أوربيت. يشعر كرفيق طويل الأمد ينمو معي.",
|
||||
"agent.welcome.suggestion.avatarHint": "استخدم {{emoji}} كالصورة الرمزية.",
|
||||
"agent.welcome.suggestion.switch": "جرّب مجموعة أخرى",
|
||||
"agent.welcome.suggestion.title": "تحتاج نقطة بداية؟ اختر واحدًا ويمكننا تحسينه لاحقًا.",
|
||||
"agent.wrapUp.action": "أعتقد أننا انتهينا",
|
||||
|
||||
+57
-1
@@ -35,6 +35,12 @@
|
||||
"builtins.lobe-agent-documents.apiName.renameDocument": "إعادة تسمية المستند",
|
||||
"builtins.lobe-agent-documents.apiName.replaceDocumentContent": "استبدال محتوى المستند",
|
||||
"builtins.lobe-agent-documents.apiName.updateLoadRule": "تحديث قاعدة التحميل",
|
||||
"builtins.lobe-agent-documents.inspector.chars": "{{count}} أحرف",
|
||||
"builtins.lobe-agent-documents.inspector.docCount": "{{count}} مستندات",
|
||||
"builtins.lobe-agent-documents.inspector.opsCount": "{{count}} عمليات",
|
||||
"builtins.lobe-agent-documents.inspector.opsResult": "{{success}}/{{total}} عمليات",
|
||||
"builtins.lobe-agent-documents.inspector.target.agent": "في الوكيل",
|
||||
"builtins.lobe-agent-documents.inspector.target.currentTopic": "في الموضوع",
|
||||
"builtins.lobe-agent-documents.title": "مستندات الوكيل",
|
||||
"builtins.lobe-agent-management.apiName.callAgent": "وكيل الاتصال",
|
||||
"builtins.lobe-agent-management.apiName.createAgent": "إنشاء وكيل",
|
||||
@@ -63,24 +69,34 @@
|
||||
"builtins.lobe-agent-management.render.installPlugin.plugin": "الملحق",
|
||||
"builtins.lobe-agent-management.render.installPlugin.success": "تم التثبيت بنجاح",
|
||||
"builtins.lobe-agent-management.title": "مدير الوكلاء",
|
||||
"builtins.lobe-agent-marketplace.apiName.showAgentMarketplace": "افتح سوق الوكلاء",
|
||||
"builtins.lobe-agent-marketplace.apiName.submitAgentPick": "إرسال اختيارات الوكلاء",
|
||||
"builtins.lobe-agent-marketplace.title": "سوق الوكلاء",
|
||||
"builtins.lobe-claude-code.agent.instruction": "تعليمات",
|
||||
"builtins.lobe-claude-code.agent.result": "النتيجة",
|
||||
"builtins.lobe-claude-code.todoWrite.allDone": "جميع المهام مكتملة",
|
||||
"builtins.lobe-claude-code.todoWrite.currentStep": "الخطوة الحالية",
|
||||
"builtins.lobe-claude-code.todoWrite.todos": "المهام",
|
||||
"builtins.lobe-cloud-sandbox.apiName.editFile": "تحرير الملف",
|
||||
"builtins.lobe-cloud-sandbox.apiName.editLocalFile": "تعديل الملف",
|
||||
"builtins.lobe-cloud-sandbox.apiName.executeCode": "تنفيذ الكود",
|
||||
"builtins.lobe-cloud-sandbox.apiName.exportFile": "تصدير الملف",
|
||||
"builtins.lobe-cloud-sandbox.apiName.getCommandOutput": "الحصول على ناتج الأمر",
|
||||
"builtins.lobe-cloud-sandbox.apiName.globFiles": "بحث شامل في الملفات",
|
||||
"builtins.lobe-cloud-sandbox.apiName.globLocalFiles": "بحث شامل في الملفات",
|
||||
"builtins.lobe-cloud-sandbox.apiName.grepContent": "البحث في المحتوى",
|
||||
"builtins.lobe-cloud-sandbox.apiName.killCommand": "إيقاف الأمر",
|
||||
"builtins.lobe-cloud-sandbox.apiName.listFiles": "قائمة الملفات",
|
||||
"builtins.lobe-cloud-sandbox.apiName.listLocalFiles": "عرض الملفات",
|
||||
"builtins.lobe-cloud-sandbox.apiName.moveFiles": "نقل الملفات",
|
||||
"builtins.lobe-cloud-sandbox.apiName.moveLocalFiles": "نقل الملفات",
|
||||
"builtins.lobe-cloud-sandbox.apiName.readFile": "قراءة محتوى الملف",
|
||||
"builtins.lobe-cloud-sandbox.apiName.readLocalFile": "قراءة محتوى الملف",
|
||||
"builtins.lobe-cloud-sandbox.apiName.renameLocalFile": "إعادة تسمية",
|
||||
"builtins.lobe-cloud-sandbox.apiName.runCommand": "تشغيل الأمر",
|
||||
"builtins.lobe-cloud-sandbox.apiName.searchFiles": "البحث في الملفات",
|
||||
"builtins.lobe-cloud-sandbox.apiName.searchLocalFiles": "البحث في الملفات",
|
||||
"builtins.lobe-cloud-sandbox.apiName.writeFile": "كتابة الملف",
|
||||
"builtins.lobe-cloud-sandbox.apiName.writeLocalFile": "كتابة الملف",
|
||||
"builtins.lobe-cloud-sandbox.inspector.noResults": "لا توجد نتائج",
|
||||
"builtins.lobe-cloud-sandbox.title": "بيئة سحابية",
|
||||
@@ -146,17 +162,24 @@
|
||||
"builtins.lobe-knowledge-base.inspector.andMoreFiles": "و{{count}} ملفًا آخر",
|
||||
"builtins.lobe-knowledge-base.inspector.noResults": "لا توجد نتائج",
|
||||
"builtins.lobe-knowledge-base.title": "المكتبة",
|
||||
"builtins.lobe-local-system.apiName.editFile": "تحرير الملف",
|
||||
"builtins.lobe-local-system.apiName.editLocalFile": "تعديل الملف",
|
||||
"builtins.lobe-local-system.apiName.getCommandOutput": "الحصول على ناتج الأمر",
|
||||
"builtins.lobe-local-system.apiName.globFiles": "بحث شامل في الملفات",
|
||||
"builtins.lobe-local-system.apiName.globLocalFiles": "بحث شامل في الملفات",
|
||||
"builtins.lobe-local-system.apiName.grepContent": "البحث في المحتوى",
|
||||
"builtins.lobe-local-system.apiName.killCommand": "إيقاف الأمر",
|
||||
"builtins.lobe-local-system.apiName.listFiles": "قائمة الملفات",
|
||||
"builtins.lobe-local-system.apiName.listLocalFiles": "عرض الملفات",
|
||||
"builtins.lobe-local-system.apiName.moveFiles": "نقل الملفات",
|
||||
"builtins.lobe-local-system.apiName.moveLocalFiles": "نقل الملفات",
|
||||
"builtins.lobe-local-system.apiName.readFile": "قراءة محتوى الملف",
|
||||
"builtins.lobe-local-system.apiName.readLocalFile": "قراءة محتوى الملف",
|
||||
"builtins.lobe-local-system.apiName.renameLocalFile": "إعادة تسمية",
|
||||
"builtins.lobe-local-system.apiName.runCommand": "تشغيل الأمر",
|
||||
"builtins.lobe-local-system.apiName.searchFiles": "البحث في الملفات",
|
||||
"builtins.lobe-local-system.apiName.searchLocalFiles": "البحث في الملفات",
|
||||
"builtins.lobe-local-system.apiName.writeFile": "كتابة الملف",
|
||||
"builtins.lobe-local-system.apiName.writeLocalFile": "كتابة الملف",
|
||||
"builtins.lobe-local-system.inspector.noResults": "لا توجد نتائج",
|
||||
"builtins.lobe-local-system.inspector.rename.result": "<old>{{oldName}}</old> → <new>{{newName}}</new>",
|
||||
@@ -233,6 +256,32 @@
|
||||
"builtins.lobe-skills.apiName.runCommand": "تشغيل الأمر",
|
||||
"builtins.lobe-skills.apiName.searchSkill": "البحث عن المهارات",
|
||||
"builtins.lobe-skills.title": "المهارات",
|
||||
"builtins.lobe-task.apiName.createTask": "إنشاء مهمة",
|
||||
"builtins.lobe-task.apiName.createTasks": "إنشاء مهام",
|
||||
"builtins.lobe-task.apiName.deleteTask": "حذف مهمة",
|
||||
"builtins.lobe-task.apiName.editTask": "تعديل مهمة",
|
||||
"builtins.lobe-task.apiName.listTasks": "عرض المهام",
|
||||
"builtins.lobe-task.apiName.runTask": "تشغيل مهمة",
|
||||
"builtins.lobe-task.apiName.runTasks": "تشغيل مهام",
|
||||
"builtins.lobe-task.apiName.updateTaskStatus": "تحديث الحالة",
|
||||
"builtins.lobe-task.apiName.viewTask": "عرض المهمة",
|
||||
"builtins.lobe-task.create.subtaskOf": "مهمة فرعية من {{parent}}",
|
||||
"builtins.lobe-task.createTasks.count": "{{count}} مهام",
|
||||
"builtins.lobe-task.createTasks.failedCount": "{{count}} فشل",
|
||||
"builtins.lobe-task.createTasks.more": "+{{count}} المزيد",
|
||||
"builtins.lobe-task.edit.assign": "تعيين",
|
||||
"builtins.lobe-task.edit.blocksOn": "يعتمد على",
|
||||
"builtins.lobe-task.edit.description": "تم تحديث الوصف",
|
||||
"builtins.lobe-task.edit.instruction": "تم تحديث التعليمات",
|
||||
"builtins.lobe-task.edit.priority": "الأولوية",
|
||||
"builtins.lobe-task.edit.rename": "إعادة تسمية",
|
||||
"builtins.lobe-task.edit.unassign": "إلغاء التعيين",
|
||||
"builtins.lobe-task.edit.unblocks": "إلغاء الاعتماد",
|
||||
"builtins.lobe-task.run.continueTopic": "متابعة الموضوع",
|
||||
"builtins.lobe-task.runTasks.count": "{{count}} مهام",
|
||||
"builtins.lobe-task.runTasks.failedCount": "{{count}} فشل",
|
||||
"builtins.lobe-task.runTasks.more": "+{{count}} المزيد",
|
||||
"builtins.lobe-task.title": "أدوات المهام",
|
||||
"builtins.lobe-topic-reference.apiName.getTopicContext": "الحصول على سياق الموضوع",
|
||||
"builtins.lobe-topic-reference.title": "مرجع الموضوع",
|
||||
"builtins.lobe-user-interaction.apiName.askUserQuestion": "طرح سؤال على المستخدم",
|
||||
@@ -260,11 +309,18 @@
|
||||
"builtins.lobe-web-browsing.inspector.noResults": "لا توجد نتائج",
|
||||
"builtins.lobe-web-browsing.title": "بحث الويب",
|
||||
"builtins.lobe-web-onboarding.apiName.finishOnboarding": "إنهاء الإعداد",
|
||||
"builtins.lobe-web-onboarding.apiName.getOnboardingState": "قراءة حالة الإعداد",
|
||||
"builtins.lobe-web-onboarding.apiName.readDocument": "قراءة المستند",
|
||||
"builtins.lobe-web-onboarding.apiName.saveUserQuestion": "حفظ سؤال المستخدم",
|
||||
"builtins.lobe-web-onboarding.apiName.updateDocument": "تحديث المستند",
|
||||
"builtins.lobe-web-onboarding.apiName.writeDocument": "كتابة المستند",
|
||||
"builtins.lobe-web-onboarding.docType.persona": "شخصية المستخدم",
|
||||
"builtins.lobe-web-onboarding.docType.soul": "SOUL.md",
|
||||
"builtins.lobe-web-onboarding.inspector.charCount_one": "{{count}} حرف",
|
||||
"builtins.lobe-web-onboarding.inspector.charCount_other": "{{count}} أحرف",
|
||||
"builtins.lobe-web-onboarding.inspector.hunkCount_one": "{{count}} تغيير",
|
||||
"builtins.lobe-web-onboarding.inspector.hunkCount_other": "{{count}} تغييرات",
|
||||
"builtins.lobe-web-onboarding.inspector.interests_one": "{{count}} اهتمام",
|
||||
"builtins.lobe-web-onboarding.inspector.interests_other": "{{count}} اهتمامات",
|
||||
"builtins.lobe-web-onboarding.title": "إعداد المستخدم",
|
||||
"confirm": "تأكيد",
|
||||
"debug.arguments": "المعلمات",
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"jina.description": "تأسست Jina AI في عام 2020، وهي شركة رائدة في مجال البحث الذكي. تشمل تقنياتها نماذج المتجهات، ومعيدو الترتيب، ونماذج لغوية صغيرة لبناء تطبيقات بحث توليدية ومتعددة الوسائط عالية الجودة.",
|
||||
"kimicodingplan.description": "كود Kimi من Moonshot AI يوفر الوصول إلى نماذج Kimi بما في ذلك K2.5 لأداء مهام الترميز.",
|
||||
"lmstudio.description": "LM Studio هو تطبيق سطح مكتب لتطوير وتجربة النماذج اللغوية الكبيرة على جهازك.",
|
||||
"lobehub.description": "يستخدم LobeHub Cloud واجهات برمجة التطبيقات الرسمية للوصول إلى نماذج الذكاء الاصطناعي ويقيس الاستخدام باستخدام أرصدة مرتبطة برموز النماذج.",
|
||||
"longcat.description": "LongCat هو سلسلة من نماذج الذكاء الاصطناعي التوليدية الكبيرة التي تم تطويرها بشكل مستقل بواسطة Meituan. تم تصميمه لتعزيز إنتاجية المؤسسة الداخلية وتمكين التطبيقات المبتكرة من خلال بنية حسابية فعالة وقدرات متعددة الوسائط قوية.",
|
||||
"minimax.description": "تأسست MiniMax في عام 2021، وتبني نماذج ذكاء اصطناعي متعددة الوسائط للأغراض العامة، بما في ذلك نماذج نصية بمليارات المعلمات، ونماذج صوتية وبصرية، بالإضافة إلى تطبيقات مثل Hailuo AI.",
|
||||
"minimaxcodingplan.description": "خطة الرموز MiniMax توفر الوصول إلى نماذج MiniMax بما في ذلك M2.7 لأداء مهام الترميز عبر اشتراك ثابت الرسوم.",
|
||||
|
||||
@@ -454,16 +454,14 @@
|
||||
"myAgents.status.published": "منشور",
|
||||
"myAgents.status.unpublished": "غير منشور",
|
||||
"myAgents.title": "وكلائي المنشورون",
|
||||
"notification.category.generation.desc": "إشعارات استكمال الصور ومقاطع الفيديو",
|
||||
"notification.category.generation.title": "الإنشاء",
|
||||
"notification.category.schedule.desc": "إخفاقات وتوقّف المهام المجدولة",
|
||||
"notification.category.schedule.title": "المهام المجدولة",
|
||||
"notification.email.desc": "تلقي إشعارات البريد الإلكتروني عند حدوث أحداث مهمة",
|
||||
"notification.email.title": "إشعارات البريد الإلكتروني",
|
||||
"notification.enabled": "مفعل",
|
||||
"notification.inbox.desc": "عرض الإشعارات في صندوق الوارد داخل التطبيق",
|
||||
"notification.inbox.title": "إشعارات صندوق الوارد",
|
||||
"notification.item.agent_cron_job_failed": "إخفاقات المهام المجدولة",
|
||||
"notification.item.agent_cron_job_failed": "فشل المهمة المجدولة",
|
||||
"notification.item.image_generation_completed": "اكتمل إنشاء الصورة",
|
||||
"notification.item.video_generation_completed": "اكتمل إنشاء الفيديو",
|
||||
"notification.title": "قنوات الإشعارات",
|
||||
@@ -498,10 +496,13 @@
|
||||
"settingAppearance.animationMode.disabled": "إيقاف",
|
||||
"settingAppearance.animationMode.elegant": "أنيق",
|
||||
"settingAppearance.animationMode.title": "رسوم استجابة التطبيق",
|
||||
"settingAppearance.appTray.desc": "عرض أيقونة LobeHub في شريط النظام أو شريط القوائم في macOS. تعطيلها يزيل أيضًا الوصول إلى قائمة الشريط.",
|
||||
"settingAppearance.appTray.title": "عرض شريط التطبيق",
|
||||
"settingAppearance.contextMenuMode.default": "افتراضي",
|
||||
"settingAppearance.contextMenuMode.desc": "تمكين قائمة النقر بزر الماوس الأيمن لبعض عناصر القائمة.",
|
||||
"settingAppearance.contextMenuMode.disabled": "معطل",
|
||||
"settingAppearance.contextMenuMode.title": "وضع قائمة النقر الأيمن",
|
||||
"settingAppearance.desktop.title": "سطح المكتب",
|
||||
"settingAppearance.neutralColor.desc": "تدرجات رمادية مخصصة مع ميول لونية مختلفة",
|
||||
"settingAppearance.neutralColor.title": "اللون المحايد",
|
||||
"settingAppearance.noAnimation.desc": "تعطيل جميع تأثيرات الرسوم المتحركة في التطبيق",
|
||||
@@ -534,6 +535,9 @@
|
||||
"settingChat.inputTemplate.desc": "سيتم ملء أحدث رسالة للمستخدم في هذا القالب",
|
||||
"settingChat.inputTemplate.placeholder": "سيتم استبدال قالب المعالجة المسبقة {{text}} بمعلومات الإدخال الفعلية",
|
||||
"settingChat.inputTemplate.title": "معالجة مسبقة لإدخال المستخدم",
|
||||
"settingChat.selfIteration.enabled.desc": "Allow this assistant to review recent signals and improve its own skills when the lab workflow runs",
|
||||
"settingChat.selfIteration.enabled.title": "Enable Self-Iteration",
|
||||
"settingChat.selfIteration.title": "Advanced Labs",
|
||||
"settingChat.submit": "تحديث تفضيلات الدردشة",
|
||||
"settingChat.title": "إعدادات الدردشة",
|
||||
"settingChatAppearance.autoScrollOnStreaming.desc": "التمرير تلقائيًا إلى الأسفل عند توليد الذكاء الاصطناعي للاستجابة",
|
||||
@@ -889,6 +893,8 @@
|
||||
"tools.builtins.lobe-agent-documents.title": "المستندات",
|
||||
"tools.builtins.lobe-agent-management.description": "إنشاء الوكلاء وإدارتهم وتنظيم عملهم",
|
||||
"tools.builtins.lobe-agent-management.title": "إدارة الوكلاء",
|
||||
"tools.builtins.lobe-agent-marketplace.description": "عرض بطاقة سوق الوكلاء المختارة للمستخدمين وتسجيل القوالب التي يختارونها.",
|
||||
"tools.builtins.lobe-agent-marketplace.title": "سوق الوكلاء",
|
||||
"tools.builtins.lobe-artifacts.description": "إنشاء ومعاينة مكونات واجهة المستخدم التفاعلية، وتصوير البيانات، والمخططات، والرسومات بصيغة SVG، وتطبيقات الويب بشكل مباشر. أنشئ محتوى بصريًا غنيًا يمكن للمستخدمين التفاعل معه مباشرة.",
|
||||
"tools.builtins.lobe-artifacts.readme": "أنشئ معاينات حية وتفاعلية لمكونات واجهة المستخدم، وتصوير البيانات، والمخططات، والرسومات بصيغة SVG، وتطبيقات الويب. أنشئ محتوى بصريًا غنيًا يمكن للمستخدمين التفاعل معه مباشرة.",
|
||||
"tools.builtins.lobe-artifacts.title": "القطع الفنية",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"table.columns.spend": "الاعتمادات",
|
||||
"table.columns.startTime": "تاريخ الإنشاء",
|
||||
"table.columns.totalTokens": "استخدام الرموز",
|
||||
"table.columns.trigger.enums.agent_signal": "إشارة الوكيل",
|
||||
"table.columns.trigger.enums.api": "استدعاء API",
|
||||
"table.columns.trigger.enums.bot": "رسالة بوت",
|
||||
"table.columns.trigger.enums.chat": "رسالة دردشة",
|
||||
@@ -23,6 +24,7 @@
|
||||
"table.columns.trigger.enums.semantic_search": "بحث المعرفة",
|
||||
"table.columns.trigger.enums.topic": "ملخص الموضوع",
|
||||
"table.columns.trigger.enums.video": "توليد الفيديو",
|
||||
"table.columns.trigger.enums.visual_analysis": "التحليل البصري",
|
||||
"table.columns.trigger.title": "المشغل",
|
||||
"table.columns.type.enums.chat": "توليد نصوص",
|
||||
"table.columns.type.enums.embedding": "تضمين",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"action.connect.popupBlocked": "تم حظر نافذة الاتصال المنبثقة. اسمح بالنوافذ المنبثقة في متصفحك للمتابعة.",
|
||||
"action.create.error": "فشل في إنشاء المهمة. يرجى المحاولة مرة أخرى.",
|
||||
"action.create.success": "تمت إضافة المهمة المجدولة. يمكنك العثور عليها في Lobe AI.",
|
||||
"action.createButton": "أضف كمهمة مجدولة",
|
||||
"action.createButton": "إضافة مهمة",
|
||||
"action.creating": "جاري الإنشاء...",
|
||||
"action.dismiss.error": "فشل في الإلغاء. يرجى المحاولة مرة أخرى.",
|
||||
"action.dismiss.tooltip": "غير مهتم",
|
||||
@@ -33,6 +33,7 @@
|
||||
"calendar-conflict-check.description": "كل صباح، افحص اليوم بحثًا عن تعارضات، اجتماعات متتالية، وقت سفر غير كافٍ.",
|
||||
"calendar-conflict-check.prompt": "كل صباح في الساعة 07:30، افحص تقويم اليوم بحثًا عن تعارضات، اجتماعات متتالية، أو وقت سفر / احتياطي غير كافٍ. اقترح حلولًا.",
|
||||
"calendar-conflict-check.title": "فحص تعارض التقويم",
|
||||
"card.templateTag": "نموذج",
|
||||
"cashflow-weekly.description": "كل يوم اثنين، ما الذي سيدخل هذا الأسبوع، ما الذي سيخرج، النفقات الكبيرة الأسبوع المقبل.",
|
||||
"cashflow-weekly.prompt": "كل يوم اثنين في الساعة 09:00، راجع التدفق النقدي: المستحقات المستحقة هذا الأسبوع، المدفوعات المستحقة، والنفقات الكبيرة المجدولة للأسبوع المقبل.",
|
||||
"cashflow-weekly.title": "التدفق النقدي الأسبوعي",
|
||||
@@ -211,6 +212,7 @@
|
||||
"repo-health-weekly.prompt": "كل يوم اثنين في الساعة 09:00، راجع مستودعات GitHub التي أديرها: تراكم القضايا، PRs المتوقفة، فشل CI، تنبيهات التبعيات. أبرز ما يحتاج إلى الانتباه هذا الأسبوع.",
|
||||
"repo-health-weekly.title": "صحة المستودعات الأسبوعية",
|
||||
"schedule.daily": "كل يوم في {{time}}",
|
||||
"schedule.editableAfterCreateTooltip": "يمكنك تعديل الجدول الزمني بعد إنشاء المهمة.",
|
||||
"schedule.weekly": "كل {{weekday}} في {{time}}",
|
||||
"section.title": "جرب هذه المهام المجدولة",
|
||||
"seo-weekly-report.description": "كل يوم اثنين، حركة الترتيب، الكلمات الرئيسية الناشئة، والصفحات التي تستحق التحديث.",
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
"localFiles.grepContent.glob": "تصفية الملفات",
|
||||
"localFiles.grepContent.pattern": "نمط البحث",
|
||||
"localFiles.grepContent.type": "نوع الملف",
|
||||
"localFiles.listFiles.emptyDirectory": "هذا المجلد فارغ",
|
||||
"localFiles.moveFiles.itemsMoved": "تم نقل {{count}} عنصر(عناصر):",
|
||||
"localFiles.moveFiles.itemsMoved_one": "تم نقل عنصر واحد:",
|
||||
"localFiles.moveFiles.itemsMoved_other": "تم نقل {{count}} عناصر:",
|
||||
@@ -129,7 +130,6 @@
|
||||
"localFiles.writeFile.characters": "أحرف",
|
||||
"localFiles.writeFile.preview": "معاينة المحتوى",
|
||||
"localFiles.writeFile.truncated": "مقتطع",
|
||||
"search.createNewSearch": "إنشاء سجل بحث جديد",
|
||||
"search.emptyResult": "لم يتم العثور على نتائج، يرجى تعديل الكلمات المفتاحية والمحاولة مرة أخرى",
|
||||
"search.genAiMessage": "إنشاء رسالة وكيل",
|
||||
"search.includedTooltip": "سيتم تضمين نتائج البحث الحالية في سياق المحادثة",
|
||||
@@ -160,7 +160,6 @@
|
||||
"search.searchTimeRange.value.week": "خلال أسبوع",
|
||||
"search.searchTimeRange.value.year": "خلال سنة",
|
||||
"search.summary": "الملخص",
|
||||
"search.summaryTooltip": "تلخيص المحتوى الحالي",
|
||||
"search.viewMoreResults": "عرض {{results}} نتيجة إضافية",
|
||||
"securityBlacklist.awsCredentials": "الوصول إلى بيانات اعتماد AWS قد يؤدي إلى تسريب مفاتيح الوصول السحابية",
|
||||
"securityBlacklist.browserCredentials": "الوصول إلى تخزين بيانات اعتماد المتصفح قد يؤدي إلى تسريب كلمات المرور",
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
"channel.userIdHint": "Вашият потребителски ID на тази платформа. AI може да го използва, за да ви изпраща директни съобщения.",
|
||||
"channel.userIdHint.discord": "Включете Developer Mode (Settings → Advanced), след това кликнете с десен бутон върху своя аватар → Copy User ID.",
|
||||
"channel.userIdHint.feishu": "Отворете вашето приложение в Feishu / Lark Open Platform → Permissions и намерете своя Open ID.",
|
||||
"channel.userIdHint.line": "Отворете LINE Developers Console → вашия канал → раздел Основни настройки и копирайте „Вашето потребителско ID“ (започва с U, 33 символа).",
|
||||
"channel.userIdHint.qq": "Вашият QQ номер, показан на страницата на вашия QQ профил.",
|
||||
"channel.userIdHint.slack": "Отворете своя Slack профил → ⋮ More → Copy member ID (започва с U).",
|
||||
"channel.userIdHint.telegram": "Изпратете произволно съобщение на @userinfobot в Telegram — той ще ви отговори с вашия числов User ID.",
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
"authModal.signIn": "Влезте отново",
|
||||
"authModal.signingIn": "Влизане...",
|
||||
"authModal.title": "Сесията е изтекла",
|
||||
"betterAuth.captcha.continue": "Продължи",
|
||||
"betterAuth.captcha.description": "Завършете проверката за сигурност по-долу. Ще продължим вашата регистрация или вход автоматично.",
|
||||
"betterAuth.captcha.pendingDescription": "Моля, първо завършете проверката, след това продължете.",
|
||||
"betterAuth.captcha.title": "Изисква се проверка за сигурност",
|
||||
"betterAuth.errors.confirmPasswordRequired": "Моля, потвърдете паролата си",
|
||||
"betterAuth.errors.emailExists": "Този имейл вече е регистриран. Моля, влезте в профила си",
|
||||
"betterAuth.errors.emailInvalid": "Моля, въведете валиден имейл адрес или потребителско име",
|
||||
|
||||
+46
-2
@@ -24,6 +24,11 @@
|
||||
"agentProfile.knowledgeBases_other": "{{count}} бази знания",
|
||||
"agentProfile.skills_one": "{{count}} умение",
|
||||
"agentProfile.skills_other": "{{count}} умения",
|
||||
"agentSignal.receipts.memory.detail": "Запазено за бъдещи отговори",
|
||||
"agentSignal.receipts.memory.title": "Паметта е запазена",
|
||||
"agentSignal.receipts.recentActivity": "Скорошна активност",
|
||||
"agentSignal.receipts.skill.detail": "Подобрено е как този асистент обработва подобни заявки",
|
||||
"agentSignal.receipts.skill.title": "Умението е актуализирано",
|
||||
"agents": "Агенти",
|
||||
"artifact.generating": "Генериране",
|
||||
"artifact.inThread": "Не може да се прегледа в подтема, моля преминете към основната зона за разговори, за да отворите",
|
||||
@@ -317,7 +322,6 @@
|
||||
"pageSelection.reference": "Избран текст",
|
||||
"pin": "Закачи",
|
||||
"pinOff": "Откачи",
|
||||
"prompts.summaryExpert": "Като експерт по обобщения, моля обобщете следното съдържание въз основа на системните подсказки по-горе:",
|
||||
"rag.referenceChunks": "Източник на препратки",
|
||||
"rag.userQuery.actions.delete": "Изтрий пренаписаното запитване",
|
||||
"rag.userQuery.actions.regenerate": "Генерирай запитване отново",
|
||||
@@ -490,6 +494,7 @@
|
||||
"taskDetail.comment.edit": "Редактиране",
|
||||
"taskDetail.comment.save": "Запази",
|
||||
"taskDetail.commentPlaceholder": "Оставете коментар...",
|
||||
"taskDetail.commentSubmitAndRun": "Изпрати и изпълни сега",
|
||||
"taskDetail.deleteConfirm.content": "Това действие не може да бъде отменено.",
|
||||
"taskDetail.deleteConfirm.ok": "Изтриване",
|
||||
"taskDetail.deleteConfirm.title": "Да изтрия ли тази задача?",
|
||||
@@ -514,6 +519,23 @@
|
||||
"taskDetail.properties": "Свойства",
|
||||
"taskDetail.reassignDisabled": "Не може да бъде преназначен агент, докато задачата се изпълнява",
|
||||
"taskDetail.rerunTask": "Повторно изпълнение",
|
||||
"taskDetail.runAll": "Изпълни всички",
|
||||
"taskDetail.runAll.cancel": "Отказ",
|
||||
"taskDetail.runAll.confirm": "Изпълни {{count}} подзадача(и)",
|
||||
"taskDetail.runAll.cycleWarning": "Открита е циклична зависимост. Задачите, участващи или блокирани от цикъла, няма да бъдат изпълнени: {{members}}",
|
||||
"taskDetail.runAll.description": "Подзадачите ще се изпълняват слой по слой. Всеки слой изчаква предишния да завърши. Задачите без зависимости се изпълняват в слой 1.",
|
||||
"taskDetail.runAll.empty": "Няма какво да се изпълни — всяка подзадача вече е завършена, в процес на изпълнение или блокирана в цикъл.",
|
||||
"taskDetail.runAll.kickedOff": "Стартирани са {{count}} подзадача(и); следващите слоеве ще последват.",
|
||||
"taskDetail.runAll.layer": "Слой {{index}}",
|
||||
"taskDetail.runAll.layerHint.first": "Започва веднага",
|
||||
"taskDetail.runAll.layerHint.next": "Изчаква слой {{prev}} да завърши",
|
||||
"taskDetail.runAll.loading": "Зареждане на план за подзадачи...",
|
||||
"taskDetail.runAll.partialFailure": "Стартирани са {{ok}} от {{total}} подзадача(и); {{failed}} неуспешни.",
|
||||
"taskDetail.runAll.skipped.alreadyDone": "{{count}} задача(и) вече завършени или отменени — пропуснати",
|
||||
"taskDetail.runAll.skipped.blockedExternally": "{{count}} задача(и) чакат блокиращ фактор извън този пакет — ще се изпълнят автоматично, когато бъдат отблокирани",
|
||||
"taskDetail.runAll.skipped.ineligible": "{{count}} задача(и) в процес на изпълнение или планирани — пропуснати",
|
||||
"taskDetail.runAll.title": "Изпълни подзадачи в ред на зависимост",
|
||||
"taskDetail.runNow": "Изпълни сега",
|
||||
"taskDetail.runTask": "Стартиране на задача",
|
||||
"taskDetail.saveModelConfig": "Запази",
|
||||
"taskDetail.status.backlog": "Изчакваща",
|
||||
@@ -599,6 +621,7 @@
|
||||
"taskSchedule.scheduleType.weekly": "Седмично",
|
||||
"taskSchedule.scheduler": "Планировчик",
|
||||
"taskSchedule.schedulerTab": "Планировчик",
|
||||
"taskSchedule.startScheduling": "Започнете планиране",
|
||||
"taskSchedule.summary.daily": "Всеки ден в {{time}}",
|
||||
"taskSchedule.summary.disabled": "Автоматизацията е изключена",
|
||||
"taskSchedule.summary.everyNHours": "На всеки {{count}} часа{{minute}}",
|
||||
@@ -762,7 +785,6 @@
|
||||
"workflow.toolDisplayName.finishOnboarding": "Завършване на въвеждането",
|
||||
"workflow.toolDisplayName.getCommandOutput": "Преглед на изхода от командата",
|
||||
"workflow.toolDisplayName.getDocument": "Прочетете документ",
|
||||
"workflow.toolDisplayName.getOnboardingState": "Проверено състояние на началното въвеждане",
|
||||
"workflow.toolDisplayName.getPageContent": "Прочитане на съдържанието на страницата",
|
||||
"workflow.toolDisplayName.getTopicContext": "Прочитане на контекста на темата",
|
||||
"workflow.toolDisplayName.globLocalFiles": "Претърсени файлове",
|
||||
@@ -786,6 +808,7 @@
|
||||
"workflow.toolDisplayName.replaceDocumentContent": "Заменено съдържание на документа",
|
||||
"workflow.toolDisplayName.replaceText": "Заменен текст",
|
||||
"workflow.toolDisplayName.runCommand": "Изпълни команда",
|
||||
"workflow.toolDisplayName.saveUserQuestion": "Записана информация",
|
||||
"workflow.toolDisplayName.search": "Претърси уеба",
|
||||
"workflow.toolDisplayName.searchAgent": "Търсени агенти",
|
||||
"workflow.toolDisplayName.searchKnowledgeBase": "Извършено търсене в базата знания",
|
||||
@@ -799,6 +822,7 @@
|
||||
"workflow.toolDisplayName.updateLoadRule": "Актуализирано правило за натоварване",
|
||||
"workflow.toolDisplayName.updatePlan": "Актуализиран план",
|
||||
"workflow.toolDisplayName.updateTodos": "Актуализирани задачи",
|
||||
"workflow.toolDisplayName.writeDocument": "Написан документ",
|
||||
"workflow.toolDisplayName.writeLocalFile": "Записа файл",
|
||||
"workflow.working": "В процес на работа...",
|
||||
"workingPanel.agentDocuments": "Agent Documents",
|
||||
@@ -830,8 +854,28 @@
|
||||
"workingPanel.resources.renameEmpty": "Title cannot be empty",
|
||||
"workingPanel.resources.renameError": "Failed to rename document",
|
||||
"workingPanel.resources.renameSuccess": "Document renamed",
|
||||
"workingPanel.resources.updatedAt": "Актуализирано {{time}}",
|
||||
"workingPanel.resources.viewMode.list": "Списъчен изглед",
|
||||
"workingPanel.resources.viewMode.tree": "Дървовиден изглед",
|
||||
"workingPanel.review.binary": "Двоичен файл — разликата не е показана",
|
||||
"workingPanel.review.collapseAll": "Свий всички",
|
||||
"workingPanel.review.copied": "Пътят е копиран",
|
||||
"workingPanel.review.copyPath": "Копирай пътя на файла",
|
||||
"workingPanel.review.empty": "Няма промени в работното дърво",
|
||||
"workingPanel.review.error": "Не може да се зареди разликата на този файл",
|
||||
"workingPanel.review.expandAll": "Разгъни всички",
|
||||
"workingPanel.review.more": "Още опции",
|
||||
"workingPanel.review.refresh": "Обнови",
|
||||
"workingPanel.review.textDiff.disable": "Деактивирай вградени текстови разлики",
|
||||
"workingPanel.review.textDiff.enable": "Активирай вградени текстови разлики",
|
||||
"workingPanel.review.title": "Преглед",
|
||||
"workingPanel.review.tooLarge": "Файлът е твърде голям за показване на разликата в линия",
|
||||
"workingPanel.review.unstaged": "Нестадирано",
|
||||
"workingPanel.review.viewMode.split": "Превключете към разделен изглед",
|
||||
"workingPanel.review.viewMode.unified": "Превключете към обединен изглед",
|
||||
"workingPanel.review.wordWrap.disable": "Деактивирай пренасяне на думи",
|
||||
"workingPanel.review.wordWrap.enable": "Активирай пренасяне на думи",
|
||||
"workingPanel.space": "Пространство",
|
||||
"workingPanel.title": "Working Panel",
|
||||
"you": "Вие",
|
||||
"zenMode": "Режим Зен"
|
||||
|
||||
@@ -448,6 +448,10 @@
|
||||
"telemetry.title": "Помогнете ни да подобрим {{appName}}",
|
||||
"temp": "Временно",
|
||||
"terms": "Условия за ползване",
|
||||
"time.formatOtherYear": "MMM D, YYYY",
|
||||
"time.formatThisYear": "MMM D",
|
||||
"time.today": "Днес",
|
||||
"time.yesterday": "Вчера",
|
||||
"unknownError": "Неизвестна грешка",
|
||||
"update": "Актуализирай",
|
||||
"updateAgent": "Актуализирай информацията за агента",
|
||||
|
||||
@@ -141,6 +141,7 @@
|
||||
"ModelSwitchPanel.detail.pricing.unit.textInput_cacheWrite": "Вход (запис в кеш)",
|
||||
"ModelSwitchPanel.detail.pricing.unit.textOutput": "Изход",
|
||||
"ModelSwitchPanel.detail.pricing.unit.videoGeneration": "Генериране на видео",
|
||||
"ModelSwitchPanel.detail.pricing.unit.videoInput": "Видео вход",
|
||||
"ModelSwitchPanel.detail.releasedAt": "Пуснат на {{date}}",
|
||||
"ModelSwitchPanel.emptyModel": "Няма активиран модел. Моля, отидете в настройките, за да активирате.",
|
||||
"ModelSwitchPanel.emptyProvider": "Няма активирани доставчици. Моля, отидете в настройките, за да активирате такъв.",
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"agentSelection.search": "Няма намерени съвпадащи агенти",
|
||||
"brief.action.acknowledge": "Потвърждаване",
|
||||
"brief.action.approve": "Одобряване",
|
||||
"brief.action.confirmDone": "Потвърди завършването",
|
||||
"brief.action.confirm": "Потвърди",
|
||||
"brief.action.confirmDone": "Потвърди",
|
||||
"brief.action.feedback": "Обратна връзка",
|
||||
"brief.action.retry": "Опит отново",
|
||||
"brief.addFeedback": "Споделяне на обратна връзка",
|
||||
@@ -22,6 +23,7 @@
|
||||
"brief.resolved": "Отбелязано като решено",
|
||||
"brief.title": "Дневен обзор",
|
||||
"brief.viewAllTasks": "Преглед на всички задачи",
|
||||
"brief.viewRun": "Преглед на изпълнението",
|
||||
"project.create": "Нов проект",
|
||||
"project.deleteConfirm": "Този проект ще бъде изтрит и не може да бъде възстановен. Потвърдете, за да продължите.",
|
||||
"starter.createAgent": "Създай агент",
|
||||
|
||||
+44
-86
@@ -84,7 +84,6 @@
|
||||
"Kimi-K2.5.description": "Kimi K2.5 е най-способният модел от серията Kimi, постигащ водещи резултати при агентни задачи, програмиране и визуално разбиране. Поддържа мултимодални входове и режими с мислене и без мислене.",
|
||||
"Kolors.description": "Kolors е модел за преобразуване на текст в изображение, разработен от екипа на Kuaishou Kolors. Обучен с милиарди параметри, той има значителни предимства във визуалното качество, разбиране на китайски семантики и визуализиране на текст.",
|
||||
"Kwai-Kolors/Kolors.description": "Kolors е мащабен латентен дифузионен модел за преобразуване на текст в изображение от екипа на Kuaishou Kolors. Обучен върху милиарди двойки текст-изображение, той се отличава с високо визуално качество, точност при сложни семантики и визуализиране на китайски/английски текст, с отлично разбиране и генериране на китайско съдържание.",
|
||||
"Kwaipilot/KAT-Dev.description": "KAT-Dev (32B) е модел с отворен код за задачи в софтуерното инженерство. Постига 62.4% успеваемост в SWE-Bench Verified, класирайки се на 5-то място сред отворените модели. Оптимизиран чрез междинно обучение, SFT и RL за допълване на код, отстраняване на грешки и преглед на код.",
|
||||
"Llama-3.2-11B-Vision-Instruct.description": "Силен визуален анализ на изображения с висока резолюция, подходящ за приложения за визуално разбиране.",
|
||||
"Llama-3.2-90B-Vision-Instruct\t.description": "Разширено визуално разсъждение за приложения с агенти за визуално разбиране.",
|
||||
"LongCat-2.0-Preview.description": "LongCat‑2.0‑Preview предлага основни функции: създаден за разработки с агенти; поддържа инструменти, многоетапно разсъждение и дълъг контекст; отличава се в генериране на код, автоматизирани работни потоци и сложни инструкции; интегриран с инструменти като Claude Code, OpenClaw, OpenCode и Kilo Code.",
|
||||
@@ -107,6 +106,7 @@
|
||||
"MiniMax-Hailuo-2.3.description": "Чисто нов модел за видео генериране с цялостни подобрения в движенията на тялото, физическата реалистичност и следването на инструкции.",
|
||||
"MiniMax-M1.description": "Нов вътрешен модел за разсъждение с 80K верига на мисълта и 1M вход, предлагащ производителност, сравнима с водещите глобални модели.",
|
||||
"MiniMax-M2-Stable.description": "Създаден за ефективно програмиране и агентски работни потоци, с по-висока едновременност за търговска употреба.",
|
||||
"MiniMax-M2.1-Lightning.description": "Мощни многоезични програмни възможности с по-бързо и ефективно извеждане.",
|
||||
"MiniMax-M2.1-highspeed.description": "Мощни многоезични програмни възможности, цялостно подобрено програмиране. По-бързо и по-ефективно.",
|
||||
"MiniMax-M2.1.description": "MiniMax-M2.1 е водеща отворена голяма езикова система от MiniMax, фокусирана върху решаването на сложни реални задачи. Основните ѝ предимства са възможностите за програмиране на множество езици и способността да действа като агент за решаване на сложни задачи.",
|
||||
"MiniMax-M2.5-highspeed.description": "MiniMax M2.5 Highspeed: Същата производителност като M2.5, но с по-бързо извеждане.",
|
||||
@@ -116,6 +116,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 е модел за хибридно внимание с отворени тегла, съдържащ 456 милиарда общи параметри и ~45.9 милиарда активни на токен. Той поддържа контекст от 1 милион токена и използва Flash Attention за намаляване на FLOPs с 75% при генериране на 100K токена спрямо DeepSeek R1. С архитектура MoE плюс CISPO и обучение с хибридно внимание RL, той постига водещи резултати в задачи за дългосрочно разсъждение и реално софтуерно инженерство.",
|
||||
"MiniMaxAI/MiniMax-M2.5.description": "MiniMax-M2.5 е най-новият голям езиков модел, разработен от MiniMax, обучен чрез мащабно подсилващо обучение в стотици хиляди сложни, реални среди. С архитектура MoE и 229 милиарда параметри, той постига водещи в индустрията резултати в задачи като програмиране, използване на инструменти от агенти, търсене и офис сценарии.",
|
||||
"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) е високоточен модел с инструкции за сложни изчисления.",
|
||||
@@ -132,7 +133,6 @@
|
||||
"Pro/MiniMaxAI/MiniMax-M2.5.description": "MiniMax-M2.5 е най-новият голям езиков модел, разработен от MiniMax, обучен чрез мащабно обучение с подсилване в стотици хиляди сложни, реални среди. С архитектура MoE и 229 милиарда параметри, той постига водещи резултати в задачи като програмиране, използване на инструменти от агенти, търсене и офис сценарии.",
|
||||
"Pro/Qwen/Qwen2.5-7B-Instruct.description": "Qwen2.5-7B-Instruct е част от най-новата серия LLM на Alibaba Cloud. Моделът с 7B параметри носи значителни подобрения в програмирането и математиката, поддържа над 29 езика и подобрява следването на инструкции, разбирането на структурирани данни и генерирането на структурирани изходи (особено JSON).",
|
||||
"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/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 г.",
|
||||
@@ -140,18 +140,18 @@
|
||||
"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/moonshotai/Kimi-K2.6.description": "Kimi K2.6 е отворен мултимодален агентен модел от Moonshot AI, който постига водещи резултати на множество основни бенчмаркове, включително HLE (с инструменти), SWE-Bench Pro и BrowseComp. Моделът използва архитектура MoE с общо 1T параметри и 32B активни параметри, поддържа контекстен прозорец от 256K токена и интегрира естествени мултимодални възможности.",
|
||||
"Pro/zai-org/GLM-5.1.description": "GLM-5.1 е следващо поколение флагмански модел, създаден за агентно инженерство, използващ архитектура Mixture of Experts (MoE) с 754B параметъра. Значително подобрява програмните способности, постигайки водещи резултати на SWE-Bench Pro, и превъзхожда предшественика си на NL2Repo и Terminal-Bench 2.0. Създаден за дълги агентни процеси, обработва неясни въпроси с по-добра преценка, разбива сложни задачи, изпълнява експерименти, анализира резултати и оптимизира решенията чрез стотици итерации и хиляди извиквания на инструменти.",
|
||||
"Pro/zai-org/glm-4.7.description": "GLM-4.7 е новото поколение водещ модел на Zhipu с 355 милиарда общи параметри и 32 милиарда активни параметри, напълно обновен за общ диалог, разсъждения и агентни способности. GLM-4.7 подобрява преплетеното мислене и въвежда запазено мислене и мислене на ниво завой.",
|
||||
"Pro/zai-org/glm-5.1.description": "GLM-5.1 е следващото поколение флагмански агентен модел на Zhipu за интелигентно инженерство. Той използва архитектура Mixture-of-Experts с 754B параметри, включваща естествено извикване на инструменти, завършване на префикси, поддръжка на FIM и контекстен прозорец от 200K за дългосрочни работни потоци.",
|
||||
"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/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 резултати в множество бенчмаркове.",
|
||||
"Qwen/Qwen-Image.description": "Qwen-Image е базов модел за генериране на изображения с 20B параметъра от екипа на Qwen. Постига значителен напредък в рендиране на сложен текст и прецизно редактиране на изображения, особено за висококачествен китайски/английски текст. Поддържа многострочни и параграфни оформления с последователна типография. Освен текстово рендиране, поддържа широк спектър от стилове – от фотореалистични до аниме, както и напреднало редактиране като трансфер на стил, добавяне/премахване на обекти, подобряване на детайли, редактиране на текст и контрол на позата, с цел да бъде цялостна основа за визуално творчество.",
|
||||
"Qwen/Qwen2-72B-Instruct.description": "Qwen 2 Instruct (72B) предоставя прецизно следване на инструкции за корпоративни натоварвания.",
|
||||
"Qwen/Qwen2-7B-Instruct.description": "Qwen2-7B-Instruct е 7B модел от серията Qwen2, обучен за следване на инструкции, използващ Transformer, SwiGLU, QKV bias и групирано внимание при заявки. Обработва големи входни данни и се представя отлично в задачи по разбиране, генериране, многоезичност, програмиране, математика и логическо мислене, надминавайки повечето отворени модели и превъзхождайки Qwen1.5-7B-Chat в множество оценки.",
|
||||
"Qwen/Qwen2-VL-72B-Instruct.description": "Qwen2-VL е най-новият модел от серията Qwen-VL, постигайки водещи резултати в задачи по компютърно зрение като MathVista, DocVQA, RealWorldQA и MTVQA. Разбира видеа с продължителност над 20 минути за видео QA, диалог и създаване на съдържание. Поддържа сложна логика и вземане на решения, интегрирайки се с устройства/роботи за действия, водени от визуална информация. Освен английски и китайски, чете текст на много езици, включително повечето европейски, японски, корейски, арабски и виетнамски.",
|
||||
"Qwen/Qwen2.5-14B-Instruct.description": "Qwen2.5-14B-Instruct е част от най-новата серия LLM на Alibaba Cloud. Моделът с 14B параметри предлага значителни подобрения в програмирането и математиката, поддържа над 29 езика и подобрява следването на инструкции, разбирането на структурирани данни и генерирането на структурирани изходи (особено JSON).",
|
||||
"Qwen/Qwen2.5-32B-Instruct.description": "Qwen2.5-32B-Instruct е част от най-новата серия LLM на Alibaba Cloud. Моделът с 32B параметри предлага значителни подобрения в програмирането и математиката, поддържа над 29 езика и подобрява следването на инструкции, разбирането на структурирани данни и генерирането на структурирани изходи (особено JSON).",
|
||||
"Qwen/Qwen2.5-72B-Instruct-128K.description": "Qwen2.5-72B-Instruct е част от най-новата серия LLM на Alibaba Cloud. Моделът с 72B параметри подобрява програмирането и математиката, поддържа до 128K вход и над 8K изход, предлага над 29 езика и подобрява следването на инструкции и структурирания изход (особено JSON).",
|
||||
@@ -160,23 +160,17 @@
|
||||
"Qwen/Qwen2.5-7B-Instruct-Turbo.description": "Qwen2.5 е ново семейство LLM, оптимизирано за задачи със стил на инструкции.",
|
||||
"Qwen/Qwen2.5-7B-Instruct.description": "Qwen2.5-7B-Instruct е част от най-новата серия LLM на Alibaba Cloud. Моделът с 7B параметри предлага значителни подобрения в програмирането и математиката, поддържа над 29 езика и подобрява следването на инструкции, разбирането на структурирани данни и генерирането на структурирани изходи (особено JSON).",
|
||||
"Qwen/Qwen2.5-Coder-32B-Instruct.description": "Qwen2.5 Coder 32B Instruct е най-новият LLM на Alibaba Cloud, фокусиран върху програмиране. Изграден върху Qwen2.5 и обучен с 5.5T токена, той значително подобрява генерирането на код, логическото мислене и поправката на грешки, като същевременно запазва силни математически и общи способности, предоставяйки стабилна основа за агенти за програмиране.",
|
||||
"Qwen/Qwen2.5-VL-32B-Instruct.description": "Qwen2.5-VL-32B-Instruct е мултимодален модел от екипа на Qwen. Разпознава често срещани обекти и анализира текст, диаграми, икони, графики и оформления. Като визуален агент, може да разсъждава и динамично да управлява инструменти, включително използване на компютър и телефон. Прецизно локализира обекти и генерира структурирани изходи за фактури и таблици. В сравнение с Qwen2-VL, RL допълнително подобрява математиката и решаването на проблеми, с по-предпочитани от хората отговори.",
|
||||
"Qwen/Qwen2.5-VL-72B-Instruct.description": "Qwen2.5-VL е модел за визия и език от серията Qwen2.5 с основни подобрения: по-силно визуално разбиране за обекти, текст, диаграми и оформления; разсъждение като визуален агент с динамично използване на инструменти; разбиране на видеа над 1 час и улавяне на ключови събития; прецизно позициониране на обекти чрез кутии или точки; и структурирани изходи за сканирани данни като фактури и таблици.",
|
||||
"Qwen/Qwen3-14B.description": "Qwen3 е следващо поколение модел Tongyi Qwen с основни подобрения в логическото мислене, общите способности, агентните възможности и многоезичната производителност, като поддържа превключване между режими на мислене.",
|
||||
"Qwen/Qwen3-235B-A22B-Instruct-2507.description": "Qwen3-235B-A22B-Instruct-2507 е водещ MoE модел от серията Qwen3 с общо 235B и 22B активни параметри. Това е актуализирана версия без мислене, фокусирана върху подобряване на следването на инструкции, логическото мислене, разбирането на текст, математика, наука, програмиране и използване на инструменти. Разширява също така многоезичните знания и се съобразява по-добре с предпочитанията на потребителите при субективни отворени задачи.",
|
||||
"Qwen/Qwen3-235B-A22B-Thinking-2507.description": "Qwen3-235B-A22B-Thinking-2507 е модел от серията Qwen3, фокусиран върху сложни логически задачи. Използва MoE архитектура с общо 235B и ~22B активни параметри на токен за повишена ефективност. Като специализиран мислещ модел, показва значителни подобрения в логика, математика, наука, програмиране и академични оценки, достигайки водещи резултати сред отворените мислещи модели. Подобрява също следването на инструкции, използването на инструменти и генерирането на текст, като нативно поддържа 256K контекст за дълбоко разсъждение и дълги документи.",
|
||||
"Qwen/Qwen3-235B-A22B.description": "Qwen3 235B A22B е ултра-мащабен модел на Qwen3, предоставящ най-високо ниво на AI възможности.",
|
||||
"Qwen/Qwen3-30B-A3B-Instruct-2507.description": "Qwen3-30B-A3B-Instruct-2507 е актуализираната немислеща версия на Qwen3-30B-A3B. Това е MoE модел с общо 30.5B и 3.3B активни параметри. Значително подобрява следването на инструкции, логическото мислене, разбирането на текст, математика, наука, програмиране и използване на инструменти, разширява многоезичните знания и се съобразява по-добре с предпочитанията на потребителите при субективни отворени задачи. Поддържа 256K контекст. Този модел е само немислещ и няма да генерира тагове `<think></think>`.",
|
||||
"Qwen/Qwen3-30B-A3B-Instruct-2507.description": "Qwen3-30B-A3B-Instruct-2507 е актуализираната версия на Qwen3-30B-A3B без мисловни способности. Това е MoE модел с общо 30.5B и 3.3B активни параметри. Значително подобрява следването на инструкции, логическото разсъждение, разбирането на текст, математиката, науката, кодирането и използването на инструменти, разширява многоезичните знания и по-добре се съобразява с предпочитанията на потребителите при субективни отворени задачи. Поддържа контекст от 256K. Този модел е само без мисловни способности и няма да изведе `נקוד` тагове.",
|
||||
"Qwen/Qwen3-30B-A3B-Thinking-2507.description": "Qwen3-30B-A3B-Thinking-2507 е най-новият мислещ модел от серията Qwen3. Това е MoE модел с общо 30.5B и 3.3B активни параметри, фокусиран върху сложни задачи. Показва значителни подобрения в логика, математика, наука, програмиране и академични оценки, и подобрява следването на инструкции, използването на инструменти, генерирането на текст и съобразяването с предпочитания. Нативно поддържа 256K контекст и може да се разшири до 1M токена. Тази версия е проектирана за мислещ режим с детайлно стъпково разсъждение и силни агентни възможности.",
|
||||
"Qwen/Qwen3-32B.description": "Qwen3 е следващо поколение модел Tongyi Qwen с основни подобрения в логическото мислене, общите способности, агентните възможности и многоезичната производителност, като поддържа превключване между режими на мислене.",
|
||||
"Qwen/Qwen3-8B.description": "Qwen3 е следващо поколение модел Tongyi Qwen с основни подобрения в логическото мислене, общите способности, агентните възможности и многоезичната производителност, като поддържа превключване между режими на мислене.",
|
||||
"Qwen/Qwen3-Coder-30B-A3B-Instruct.description": "Qwen3-Coder-30B-A3B-Instruct е модел за програмиране от серията Qwen3, разработен от екипа на Qwen. Той е оптимизиран за висока производителност и ефективност, като същевременно подобрява възможностите за работа с код. Демонстрира силни предимства при агентно програмиране, автоматизирани операции в браузър и използване на инструменти сред отворените модели. Поддържа нативно контекст от 256K токена и може да се разшири до 1M токена за разбиране на цели кодови бази. Използва се за агентно програмиране в платформи като Qwen Code и CLINE с посветен формат за извикване на функции.",
|
||||
"Qwen/Qwen3-Coder-480B-A35B-Instruct.description": "Qwen3-Coder-480B-A35B-Instruct е най-агентният модел за програмиране на Alibaba до момента. Това е MoE модел с общо 480 милиарда параметъра и 35 милиарда активни, осигуряващ баланс между ефективност и производителност. Поддържа нативно контекст от 256K токена и може да се разшири до 1M токена чрез YaRN, което позволява работа с големи кодови бази. Създаден е за агентни работни потоци при програмиране и може да взаимодейства с инструменти и среди за решаване на сложни задачи. Постига водещи резултати сред отворените модели в бенчмаркове за програмиране и агенти, сравними с Claude Sonnet 4.",
|
||||
"Qwen/Qwen3-Omni-30B-A3B-Captioner.description": "Qwen3-Omni-30B-A3B-Captioner е VLM модел от серията Qwen3, създаден за висококачествени, детайлни и точни описания на изображения. Използва MoE архитектура с 30 милиарда параметъра за дълбоко разбиране на изображения и генериране на плавни описания, като се отличава в улавянето на детайли, разбиране на сцени, разпознаване на обекти и логически връзки.",
|
||||
"Qwen/Qwen3-Omni-30B-A3B-Instruct.description": "Qwen3-Omni-30B-A3B-Instruct е MoE модел от серията Qwen3 с общо 30 милиарда и 3 милиарда активни параметъра, осигуряващ висока производителност при ниска цена на инференция. Обучен е върху висококачествени многоезични данни от различни източници и поддържа пълноформатни входове (текст, изображения, аудио, видео), както и кросмодално разбиране и генериране.",
|
||||
"Qwen/Qwen3-Omni-30B-A3B-Thinking.description": "Qwen3-Omni-30B-A3B-Thinking е основният компонент „Мислител“ на Qwen3-Omni. Обработва мултимодални входове (текст, аудио, изображения, видео) и извършва сложни разсъждения чрез верига от мисли, обединявайки входовете в споделено представяне за дълбоко кросмодално разбиране. Това е MoE модел с 30 милиарда общи и 3 милиарда активни параметъра, балансиращ силни разсъждения и изчислителна ефективност.",
|
||||
"Qwen/Qwen3-VL-235B-A22B-Instruct.description": "Qwen3-VL-235B-A22B-Instruct е голям модел от серията Qwen3-VL, настроен за инструкции и изграден върху MoE архитектура, осигуряващ отлично мултимодално разбиране и генериране. Поддържа нативно контекст от 256K токена и е подходящ за високонагружени производствени мултимодални услуги.",
|
||||
"Qwen/Qwen3-VL-235B-A22B-Thinking.description": "Qwen3-VL-235B-A22B-Thinking е водещата версия за разсъждение на Qwen3-VL, оптимизирана за сложни мултимодални разсъждения, дълъг контекст и взаимодействие с агенти в корпоративни сценарии.",
|
||||
"Qwen/Qwen3-VL-30B-A3B-Instruct.description": "Qwen3-VL-30B-A3B-Instruct е настроен за инструкции модел от серията Qwen3-VL с високо ниво на разбиране и генериране на визия и език. Поддържа нативно контекст от 256K токена за мултимодален чат и генериране, базирано на изображения.",
|
||||
"Qwen/Qwen3-VL-30B-A3B-Thinking.description": "Qwen3-VL-30B-A3B-Thinking е версия с подобрени разсъждения на Qwen3-VL, оптимизирана за мултимодални разсъждения, преобразуване на изображения в код и сложно визуално разбиране. Поддържа контекст от 256K токена с по-силна способност за верига от мисли.",
|
||||
"Qwen/Qwen3-VL-32B-Instruct.description": "Qwen3-VL-32B-Instruct е модел за визия и език от екипа на Qwen с водещи резултати в множество VL бенчмаркове. Поддържа изображения с мегапикселова резолюция и предлага силно визуално разбиране, многоезичен OCR, прецизно визуално позициониране и визуален диалог. Обработва сложни мултимодални задачи и поддържа извикване на инструменти и допълване на префикси.",
|
||||
@@ -189,6 +183,7 @@
|
||||
"Qwen/Qwen3.5-397B-A17B.description": "Qwen3.5-397B-A17B е най-новият модел за визия и език в серията Qwen3.5, използващ архитектура Mixture-of-Experts (MoE) с общо 397 милиарда параметри и 17 милиарда активни параметри. Той нативно поддържа дължина на контекста от 256K с разширяемост до приблизително 1 милион токени, поддържа 201 езика и предоставя унифицирано разбиране на визия и език, извикване на инструменти и способности за разсъждение.",
|
||||
"Qwen/Qwen3.5-4B.description": "Qwen3.5-4B е роден мултимодален голям езиков модел от екипа на Qwen с 4 милиарда параметри, най-леката плътна архитектура в серията Qwen3.5. Той използва ефективна хибридна архитектура, комбинираща Gated Delta Networks и Gated Attention, като нативно поддържа дължина на контекста от 256K с разширяемост до приблизително 1 милион токени.",
|
||||
"Qwen/Qwen3.5-9B.description": "Qwen3.5-9B е роден мултимодален голям езиков модел от екипа на Qwen с 9 милиарда параметри. Като лек плътен модел в серията Qwen3.5, той използва ефективна хибридна архитектура, комбинираща Gated Delta Networks и Gated Attention, като нативно поддържа дължина на контекста от 256K с разширяемост до приблизително 1 милион токени.",
|
||||
"Qwen/Qwen3.6-27B.description": "Qwen3.6-27B е първият отворен среден плътен модел от серията Qwen3.6, с ключови подобрения за генериране на код, работни потоци на агенти и реални сценарии за разработка. В сравнение с Qwen3.5-27B, този модел показва значителни подобрения в разработката на фронтенд, разсъждения на ниво хранилище, извикване на инструменти и решаване на сложни проблеми, с ново добавени оптимизации за историческо разсъждение.",
|
||||
"Qwen/Qwen3.6-35B-A3B.description": "Qwen3.6-35B-A3B е голям езиков модел от екипа на Qwen от серията Qwen3.6, използващ Mixture-of-Experts (MoE) архитектура с общо 35B параметъра и 3B активни параметъра. Той балансира ефективното инфериране с отлично представяне и поддържа както мислещ, така и немислещ режим, което позволява гъвкаво превключване между бърз отговор и задълбочено разсъждение.",
|
||||
"Qwen2-72B-Instruct.description": "Qwen2 е най-новата версия от серията Qwen, поддържаща контекстен прозорец от 128k. В сравнение с най-добрите отворени модели днес, Qwen2-72B значително превъзхожда водещите модели в разбирането на естествен език, знания, програмиране, математика и многоезични възможности.",
|
||||
"Qwen2-7B-Instruct.description": "Qwen2 е най-новата версия от серията Qwen, която превъзхожда най-добрите отворени модели със сходен или дори по-голям размер. Qwen2 7B показва значителни предимства в множество бенчмаркове, особено в програмиране и разбиране на китайски език.",
|
||||
@@ -296,13 +291,11 @@
|
||||
"anthropic/claude-opus-4.description": "Opus 4 е флагманският модел на Anthropic, проектиран за сложни задачи и корпоративни приложения.",
|
||||
"anthropic/claude-sonnet-4.5.description": "Claude Sonnet 4.5 е най-новият хибриден модел за логическо мислене на Anthropic, оптимизиран за сложни разсъждения и програмиране.",
|
||||
"anthropic/claude-sonnet-4.description": "Claude Sonnet 4 е хибриден модел за логическо мислене на Anthropic с комбинирани способности за мислене и бързи отговори.",
|
||||
"ascend-tribe/pangu-pro-moe.description": "Pangu-Pro-MoE 72B-A16B е разреден LLM с общо 72 милиарда и 16 милиарда активни параметри, базиран на групирана MoE (MoGE) архитектура. Групира експерти при избора и ограничава токените да активират равен брой експерти на група, което балансира натоварването и подобрява ефективността на внедряване върху Ascend.",
|
||||
"aya.description": "Aya 23 е многоезичен модел на Cohere, поддържащ 23 езика за разнообразни приложения.",
|
||||
"aya:35b.description": "Aya 23 е многоезичен модел на Cohere, поддържащ 23 езика за разнообразни приложения.",
|
||||
"azure-DeepSeek-R1-0528.description": "Разположен от Microsoft; DeepSeek R1 е надграден до DeepSeek-R1-0528. Актуализацията увеличава изчислителната мощ и оптимизациите след обучение, значително подобрявайки дълбочината на разсъждение и извеждането. Представя се отлично в тестове по математика, програмиране и логика, доближавайки се до водещи модели като O3 и Gemini 2.5 Pro.",
|
||||
"baichuan-m2-32b.description": "Baichuan M2 32B е MoE модел от Baichuan Intelligence със силни способности за разсъждение.",
|
||||
"baichuan/baichuan2-13b-chat.description": "Baichuan-13B е отворен, търговски използваем LLM с 13 милиарда параметри от Baichuan, постигайки водещи резултати за своя размер в авторитетни китайски и английски тестове.",
|
||||
"baidu/ERNIE-4.5-300B-A47B.description": "ERNIE-4.5-300B-A47B е MoE LLM на Baidu с общо 300 милиарда параметри и 47 милиарда активни на токен, балансирайки висока производителност и изчислителна ефективност. Като основен модел от серията ERNIE 4.5, той се отличава в разбиране, генериране, разсъждение и програмиране. Използва мултимодален хетерогенен MoE метод за предварително обучение с комбинирано текстово и визуално обучение за повишаване на цялостните способности, особено при следване на инструкции и световни знания.",
|
||||
"baidu/ernie-5.0-thinking-preview.description": "ERNIE 5.0 Thinking Preview е следващото поколение нативен мултимодален модел на Baidu, силен в мултимодално разбиране, следване на инструкции, създаване, фактологични въпроси и отговори и използване на инструменти.",
|
||||
"big-pickle.description": "Big Pickle от OpenCode — безплатен модел с отворени тегла и силни програмни способности.",
|
||||
"black-forest-labs/flux-1.1-pro.description": "FLUX 1.1 Pro е по-бърза, подобрена версия на FLUX Pro с отлично качество на изображенията и спазване на подканите.",
|
||||
@@ -315,6 +308,7 @@
|
||||
"c4ai-aya-vision-8b.description": "Aya Vision е авангарден мултимодален модел, който се представя отлично в ключови езикови, текстови и визуални тестове. Тази версия с 8 милиарда параметри е фокусирана върху ниска латентност и силна производителност.",
|
||||
"charglm-3.description": "CharGLM-3 е създаден за ролеви игри и емоционално общуване, поддържа ултра-дълга многозавойна памет и персонализиран диалог.",
|
||||
"charglm-4.description": "CharGLM-4 е създаден за ролеви игри и емоционално общуване, поддържа ултра-дълга многозавойна памет и персонализиран диалог.",
|
||||
"chat-latest.description": "Най-новият моментален модел, използван в ChatGPT.",
|
||||
"chatgpt-4o-latest.description": "ChatGPT-4o е динамичен модел, актуализиран в реално време. Той комбинира силно разбиране на езика и генериране за мащабни случаи на употреба като клиентска поддръжка, образование и техническа помощ.",
|
||||
"claude-2.0.description": "Claude 2 предлага ключови подобрения за предприятия, включително водещ контекст от 200 000 токена, намалени халюцинации, системни подканвания и нова тестова функция: използване на инструменти.",
|
||||
"claude-2.1.description": "Claude 2 предлага ключови подобрения за предприятия, включително водещ контекст от 200 000 токена, намалени халюцинации, системни подканвания и нова тестова функция: използване на инструменти.",
|
||||
@@ -326,13 +320,13 @@
|
||||
"claude-3-haiku-20240307.description": "Claude 3 Haiku е най-бързият и най-компактен модел на Anthropic, проектиран за почти мигновени отговори с бърза и точна производителност.",
|
||||
"claude-3-opus-20240229.description": "Claude 3 Opus е най-мощният модел на Anthropic за силно сложни задачи, отличаващ се с производителност, интелигентност, плавност и разбиране.",
|
||||
"claude-3-sonnet-20240229.description": "Claude 3 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 от Anthropic — ново поколение Haiku с подобрено разсъждение и визия.",
|
||||
"claude-haiku-4.5.description": "Claude Haiku 4.5 е най-бързият и най-умен Haiku модел на Anthropic, с мълниеносна скорост и разширено разсъждение.",
|
||||
"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-1-20250805.description": "Claude Opus 4.1 е най-новият и най-способен модел на Anthropic за изключително сложни задачи, отличаващ се с производителност, интелигентност, плавност и разбиране.",
|
||||
"claude-opus-4-1.description": "Claude Opus 4.1 от Anthropic — премиум модел за дълбок анализ и разсъждение.",
|
||||
"claude-opus-4-20250514.description": "Claude Opus 4 е най-мощният модел на Anthropic за комплексни задачи, с изключителна производителност, интелигентност и разбиране.",
|
||||
"claude-opus-4-20250514.description": "Claude Opus 4 е най-мощният модел на Anthropic за изключително сложни задачи, отличаващ се с производителност, интелигентност, плавност и разбиране.",
|
||||
"claude-opus-4-5-20251101.description": "Claude Opus 4.5 е флагманският модел на Anthropic, комбиниращ изключителна интелигентност с мащабируема производителност, идеален за сложни задачи, изискващи най-висококачествени отговори и разсъждение.",
|
||||
"claude-opus-4-5.description": "Claude Opus 4.5 от Anthropic — флагмански модел с върхово разсъждение и кодови умения.",
|
||||
"claude-opus-4-6.description": "Claude Opus 4.6 от Anthropic — флагман с 1M контекст и усъвършенствано разсъждение.",
|
||||
@@ -341,7 +335,7 @@
|
||||
"claude-opus-4.6-fast.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 може да дава мигновени отговори или разширени стъпкови разсъждения с видим процес.",
|
||||
"claude-sonnet-4-20250514.description": "Claude Sonnet 4 е най-интелигентният модел на Anthropic досега, предлагащ почти мигновени отговори или разширено стъпка по стъпка мислене с фино управление за API потребители.",
|
||||
"claude-sonnet-4-5-20250929.description": "Claude Sonnet 4.5 е най-интелигентният модел на Anthropic досега.",
|
||||
"claude-sonnet-4-5.description": "Claude Sonnet 4.5 от Anthropic — подобрен Sonnet с по‑силни кодови способности.",
|
||||
"claude-sonnet-4-6.description": "Claude Sonnet 4.6 от Anthropic — последният Sonnet с превъзходно кодиране и работа с инструменти.",
|
||||
@@ -405,24 +399,20 @@
|
||||
"deepseek-ai/DeepSeek-R1-Distill-Llama-70B.description": "Дестилираните модели DeepSeek-R1 използват RL и cold-start данни за подобряване на разсъждението и поставят нови бенчмарк стандарти за отворени модели с много задачи.",
|
||||
"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 за модел с 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 за по-надеждно използване на инструменти и многоетапни задачи.",
|
||||
"deepseek-ai/DeepSeek-V3.1.description": "DeepSeek V3.1 използва хибридна архитектура за разсъждение и поддържа както мислещ, така и немислещ режим.",
|
||||
"deepseek-ai/DeepSeek-V3.2-Exp.description": "DeepSeek V3.2 Exp използва хибридна архитектура за разсъждение и поддържа както мисловни, така и немисловни режими.",
|
||||
"deepseek-ai/DeepSeek-V3.2.description": "DeepSeek-V3.2 е модел, който съчетава висока изчислителна ефективност с отлично разсъждение и производителност като агент. Подходът му се основава на три основни технологични пробива: DeepSeek Sparse Attention (DSA), ефективен механизъм за внимание, който значително намалява изчислителната сложност, като същевременно поддържа производителността на модела и е специално оптимизиран за сценарии с дълъг контекст; мащабируема рамка за подсилващо обучение, чрез която производителността на модела може да съперничи на GPT-5, а версията с висока изчислителна мощност може да съперничи на Gemini-3.0-Pro по способности за разсъждение; и мащабна тръбопроводна система за синтез на задачи за агенти, предназначена да интегрира способности за разсъждение в сценарии за използване на инструменти, като по този начин подобрява следването на инструкции и обобщаването в сложни интерактивни среди. Моделът постигна златни медали на Международната математическа олимпиада (IMO) и Международната олимпиада по информатика (IOI) през 2025 г.",
|
||||
"deepseek-ai/DeepSeek-V3.description": "DeepSeek-V3 е MoE модел с 671 милиарда параметъра, използващ MLA и DeepSeekMoE с балансирано натоварване без загуби за ефективно обучение и извеждане. Предварително обучен върху 14.8 трилиона висококачествени токени със SFT и RL, той превъзхожда други отворени модели и се доближава до водещите затворени модели.",
|
||||
"deepseek-ai/DeepSeek-V4-Flash.description": "DeepSeek-V4-Flash е предварителна версия на MoE езиковия модел от серията DeepSeek-V4. Общият размер на параметрите е 284B, размерът на активните параметри е 13B и поддържа ултра-дълъг контекст от 1M токена. Моделът използва хибридна архитектура за внимание, която комбинира CSA и HCA, и въвежда mHC и Muon Optimizer за подобряване на ефективността на разсъжденията в дълъг контекст, стабилността на обучението и общата производителност.",
|
||||
"deepseek-ai/deepseek-llm-67b-chat.description": "DeepSeek LLM Chat (67B) е иновативен модел, предлагащ дълбоко езиково разбиране и интеракция.",
|
||||
"deepseek-ai/deepseek-v3.1-terminus.description": "DeepSeek V3.1 е модел за разсъждение от ново поколение с по-силни способности за сложни разсъждения и верига от мисли за задълбочени аналитични задачи.",
|
||||
"deepseek-ai/deepseek-v3.1.description": "DeepSeek V3.1 е модел за разсъждение от ново поколение с по-силни способности за сложни разсъждения и верига от мисли за задълбочени аналитични задачи.",
|
||||
"deepseek-ai/deepseek-v3.2.description": "DeepSeek V3.2 е модел за разсъждение от следващо поколение с по-силни способности за сложни разсъждения и верига на мисълта.",
|
||||
"deepseek-chat.description": "Нов модел с отворен код, комбиниращ общи и програмни способности. Запазва диалоговите умения на чат модела и силното кодиране на coder версията, с по-добра подравненост на предпочитанията. DeepSeek‑V2.5 подобрява писане и следване на инструкции.",
|
||||
"deepseek-chat.description": "Съвместим псевдоним за режим без мислене на DeepSeek V4 Flash. Планирано за премахване — използвайте DeepSeek V4 Flash вместо това.",
|
||||
"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.",
|
||||
"deepseek-ocr.description": "DeepSeek-OCR е визионно-езиков модел от DeepSeek AI, фокусиран върху OCR и „контекстуална оптична компресия“. Изследва компресиране на контекстуална информация от изображения, ефективно обработва документи и ги преобразува в структурирани текстови формати като Markdown. Прецизно разпознава текст в изображения, което го прави идеален за дигитализация на документи, извличане на текст и структурирана обработка.",
|
||||
"deepseek-r1-0528.description": "Пълен модел с 685 милиарда параметъра, пуснат на 28.05.2025. DeepSeek-R1 използва мащабно подсилено обучение след предварителното обучение, значително подобрявайки разсъждението с минимални етикетирани данни и се представя силно в математика, програмиране и езиково разсъждение.",
|
||||
"deepseek-r1-250528.description": "DeepSeek R1 250528 е пълният модел за разсъждение на DeepSeek-R1, предназначен за трудни математически и логически задачи.",
|
||||
"deepseek-r1-70b-fast-online.description": "DeepSeek R1 70B бързо издание с търсене в реално време в уеб, осигуряващо по-бързи отговори при запазване на производителността.",
|
||||
@@ -441,7 +431,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 V4 Flash (thinking). Предстои да бъде премахнат — използвайте deepseek-v4-flash.",
|
||||
"deepseek-reasoner.description": "Съвместим псевдоним за режим с мислене на DeepSeek V4 Flash. Планирано за премахване — използвайте DeepSeek V4 Flash вместо това.",
|
||||
"deepseek-v2.description": "DeepSeek V2 е ефективен MoE модел за икономична обработка.",
|
||||
"deepseek-v2:236b.description": "DeepSeek V2 236B е модел на DeepSeek, фокусиран върху програмиране, с висока производителност при генериране на код.",
|
||||
"deepseek-v3-0324.description": "DeepSeek-V3-0324 е MoE модел с 671 милиарда параметъра, с изключителни способности в програмиране, технически задачи, разбиране на контекст и обработка на дълги текстове.",
|
||||
@@ -460,19 +450,16 @@
|
||||
"deepseek-vl2-small.description": "DeepSeek VL2 Small е лек мултимодален вариант за среди с ограничени ресурси и висока едновременност.",
|
||||
"deepseek-vl2.description": "DeepSeek VL2 е мултимодален модел за разбиране на изображения и текст и прецизни визуални въпроси и отговори.",
|
||||
"deepseek/deepseek-chat-v3-0324.description": "DeepSeek V3 е MoE модел с 685 милиарда параметъра и най-новата итерация от водещата чат серия на DeepSeek.\n\nНадгражда [DeepSeek V3](/deepseek/deepseek-chat-v3) и се представя отлично в различни задачи.",
|
||||
"deepseek/deepseek-chat-v3-0324:free.description": "DeepSeek V3 е MoE модел с 685 милиарда параметъра и най-новата итерация от водещата чат серия на DeepSeek.\n\nНадгражда [DeepSeek V3](/deepseek/deepseek-chat-v3) и се представя отлично в различни задачи.",
|
||||
"deepseek/deepseek-chat-v3.1.description": "DeepSeek-V3.1 е хибриден модел за разсъждение с дълъг контекст от DeepSeek, поддържащ смесени режими на мислене/без мислене и интеграция с инструменти.",
|
||||
"deepseek/deepseek-chat.description": "DeepSeek-V3 е високоефективен хибриден модел за разсъждение от DeepSeek, предназначен за сложни задачи и интеграция с инструменти.",
|
||||
"deepseek/deepseek-math-v2.description": "DeepSeek Math V2 е модел, който постига значителни пробиви в способностите за математическо разсъждение. Основната му иновация е в механизма за обучение чрез „самопроверка“ и е достигнал ниво на златен медал в няколко от най-престижните математически състезания.",
|
||||
"deepseek/deepseek-r1-0528.description": "DeepSeek R1 0528 е обновен вариант, фокусиран върху отворен достъп и по-дълбоко разсъждение.",
|
||||
"deepseek/deepseek-r1-0528:free.description": "DeepSeek-R1 значително подобрява разсъждението с минимално етикетирани данни и извежда верига от мисли преди крайния отговор за повишаване на точността.",
|
||||
"deepseek/deepseek-r1-distill-llama-70b.description": "DeepSeek R1 Distill Llama 70B е дестилиран LLM, базиран на Llama 3.3 70B, фино настроен с изходи от DeepSeek R1 за постигане на конкурентна производителност спрямо водещите модели.",
|
||||
"deepseek/deepseek-r1-distill-llama-8b.description": "DeepSeek R1 Distill Llama 8B е дестилиран LLM, базиран на Llama-3.1-8B-Instruct, обучен с изходи от DeepSeek R1.",
|
||||
"deepseek/deepseek-r1-distill-qwen-14b.description": "DeepSeek R1 Distill Qwen 14B е дестилиран LLM, базиран на Qwen 2.5 14B, обучен с изходи от DeepSeek R1. Надминава OpenAI o1-mini в множество бенчмаркове, постигайки водещи резултати сред плътните модели. Основни резултати:\nAIME 2024 pass@1: 69.7\nMATH-500 pass@1: 93.9\nCodeForces рейтинг: 1481\nФиното настройване с изходи от DeepSeek R1 осигурява конкурентна производителност спрямо по-големи модели.",
|
||||
"deepseek/deepseek-r1-distill-qwen-32b.description": "DeepSeek R1 Distill Qwen 32B е дестилиран LLM, базиран на Qwen 2.5 32B, обучен с изходи от DeepSeek R1. Надминава OpenAI o1-mini в множество бенчмаркове, постигайки водещи резултати сред плътните модели. Основни резултати:\nAIME 2024 pass@1: 72.6\nMATH-500 pass@1: 94.3\nCodeForces рейтинг: 1691\nФиното настройване с изходи от DeepSeek R1 осигурява конкурентна производителност спрямо по-големи модели.",
|
||||
"deepseek/deepseek-r1.description": "DeepSeek R1 е обновен до DeepSeek-R1-0528. С повече изчислителна мощ и алгоритмични оптимизации след обучение, значително подобрява дълбочината и способността за разсъждение. Представя се отлично в бенчмаркове по математика, програмиране и логика, доближавайки се до водещи модели като o3 и Gemini 2.5 Pro.",
|
||||
"deepseek/deepseek-r1/community.description": "DeepSeek R1 е най-новият модел с отворен код, пуснат от екипа на DeepSeek, с много силна производителност в разсъждението, особено в математика, програмиране и логически задачи, сравним с OpenAI o1.",
|
||||
"deepseek/deepseek-r1:free.description": "DeepSeek-R1 значително подобрява разсъждението с минимално етикетирани данни и извежда верига от мисли преди крайния отговор за повишаване на точността.",
|
||||
"deepseek/deepseek-reasoner.description": "DeepSeek-V3 Thinking (reasoner) е експериментален модел за разсъждение от DeepSeek, подходящ за задачи с висока сложност.",
|
||||
"deepseek/deepseek-v3.description": "Бърз универсален LLM с подобрено разсъждение.",
|
||||
"deepseek/deepseek-v3/community.description": "DeepSeek-V3 постига значителен пробив в скоростта на разсъждение спрямо предишни модели. Класира се на първо място сред моделите с отворен код и съперничи на най-напредналите затворени модели. DeepSeek-V3 използва Multi-Head Latent Attention (MLA) и архитектурата DeepSeekMoE, и двете напълно валидирани в DeepSeek-V2. Въвежда и беззагубна помощна стратегия за балансиране на натоварването и цел за обучение с предсказване на множество токени за по-силна производителност.",
|
||||
@@ -485,18 +472,11 @@
|
||||
"doubao-1.5-lite-32k.description": "Doubao-1.5-lite е нов лек модел с изключително бърз отговор, предоставящ първокласно качество и ниска латентност.",
|
||||
"doubao-1.5-pro-256k.description": "Doubao-1.5-pro-256k е цялостен ъпгрейд на Doubao-1.5-Pro, подобряващ общата производителност с 10%. Поддържа контекстен прозорец от 256k и до 12k изходни токена, осигурявайки по-висока производителност, по-голям прозорец и отлична стойност за по-широки приложения.",
|
||||
"doubao-1.5-pro-32k.description": "Doubao-1.5-pro е флагмански модел от ново поколение с цялостни подобрения, отличаващ се в знания, програмиране и разсъждение.",
|
||||
"doubao-1.5-thinking-pro-m.description": "Doubao-1.5 е нов дълбок разсъждаващ модел (версия m включва родно мултимодално дълбоко разсъждение), който се отличава в математика, програмиране, научно разсъждение и общи задачи като творческо писане. Достига или доближава водещи резултати в бенчмаркове като AIME 2024, Codeforces и GPQA. Поддържа контекстен прозорец от 128k и 16k изход.",
|
||||
"doubao-1.5-thinking-pro.description": "Doubao-1.5 е нов дълбок разсъждаващ модел, който се отличава в математика, програмиране, научно разсъждение и общи задачи като творческо писане. Достига или доближава водещи резултати в бенчмаркове като AIME 2024, Codeforces и GPQA. Поддържа контекстен прозорец от 128k и 16k изход.",
|
||||
"doubao-1.5-thinking-vision-pro.description": "Нов визуален дълбок разсъждаващ модел със засилено мултимодално разбиране и разсъждение, постигайки SOTA резултати в 37 от 59 публични бенчмарка.",
|
||||
"doubao-1.5-ui-tars.description": "Doubao-1.5-UI-TARS е роден агентен модел, фокусиран върху графичен интерфейс, който безпроблемно взаимодейства с интерфейси чрез човешко възприятие, разсъждение и действие.",
|
||||
"doubao-1.5-vision-lite.description": "Doubao-1.5-vision-lite е подобрен мултимодален модел, който поддържа изображения с всякаква резолюция и екстремни съотношения, подобрявайки визуалното разсъждение, разпознаването на документи, разбиране на детайли и следване на инструкции. Поддържа контекстен прозорец от 128k и до 16k изходни токена.",
|
||||
"doubao-1.5-vision-pro-32k.description": "Doubao-1.5-vision-pro е подобрен мултимодален модел, който поддържа изображения с всякаква резолюция и екстремни съотношения, подобрявайки визуалното разсъждение, разпознаването на документи, разбиране на детайли и следване на инструкции.",
|
||||
"doubao-1.5-vision-pro.description": "Doubao-1.5-vision-pro е подобрен мултимодален модел, който поддържа изображения с всякаква резолюция и екстремни съотношения, подобрявайки визуалното разсъждение, разпознаването на документи, разбиране на детайли и следване на инструкции.",
|
||||
"doubao-lite-32k.description": "Изключително бърз отговор с по-добра стойност, предлагащ по-гъвкави възможности в различни сценарии. Поддържа разсъждение и фина настройка с контекстен прозорец от 32k.",
|
||||
"doubao-pro-32k.description": "Най-добре представящият се флагмански модел за сложни задачи, с отлични резултати в справочни въпроси, обобщение, създаване, класификация на текст и ролеви игри. Поддържа разсъждение и фина настройка с контекстен прозорец от 32k.",
|
||||
"doubao-seed-1.6-flash.description": "Doubao-Seed-1.6-flash е изключително бърз мултимодален дълбок разсъждаващ модел с TPOT до 10ms. Поддържа текст и визия, надминава предишния lite модел в разбиране на текст и съответства на конкурентни pro модели във визия. Поддържа контекстен прозорец от 256k и до 16k изходни токена.",
|
||||
"doubao-seed-1.6-lite.description": "Doubao-Seed-1.6-lite е нов мултимодален дълбок разсъждаващ модел с регулируемо усилие на разсъждение (Минимално, Ниско, Средно, Високо), осигуряващ по-добра стойност и силен избор за обичайни задачи, с контекстен прозорец до 256k.",
|
||||
"doubao-seed-1.6-thinking.description": "Doubao-Seed-1.6 значително засилва разсъждението, допълнително подобрявайки основните способности в програмиране, математика и логическо мислене спрямо Doubao-1.5-thinking-pro, като добавя и разбиране на визия. Поддържа контекстен прозорец от 256k и до 16k изходни токена.",
|
||||
"doubao-seed-1.6-vision.description": "Doubao-Seed-1.6-vision е визуален дълбок разсъждаващ модел, който осигурява по-силно мултимодално разбиране и разсъждение за образование, преглед на изображения, инспекция/сигурност и AI търсене с въпроси и отговори. Поддържа контекстен прозорец от 256k и до 64k изходни токена.",
|
||||
"doubao-seed-1.6.description": "Doubao-Seed-1.6 е нов мултимодален дълбок разсъждаващ модел с режими auto, thinking и non-thinking. В non-thinking режим значително превъзхожда Doubao-1.5-pro/250115. Поддържа контекстен прозорец от 256k и до 16k изходни токена.",
|
||||
"doubao-seed-1.8.description": "Doubao-Seed-1.8 притежава по-силно мултимодално разбиране и агентни способности, поддържа вход от текст/изображение/видео и кеширане на контекст, като осигурява отлична производителност при сложни задачи.",
|
||||
@@ -512,31 +492,25 @@
|
||||
"doubao-seedance-1-5-pro-251215.description": "Seedance 1.5 Pro от ByteDance поддържа текст-към-видео, изображение-към-видео (първи кадър, първи+последен кадър) и аудио генериране, синхронизирано с визуализации.",
|
||||
"doubao-seedance-2-0-260128.description": "Seedance 2.0 от ByteDance е най-мощният модел за видео генериране, поддържащ мултимодално генериране на референтни видеа, редактиране на видеа, разширение на видеа, преобразуване на текст във видео и преобразуване на изображение във видео със синхронизиран звук.",
|
||||
"doubao-seedance-2-0-fast-260128.description": "Seedance 2.0 Fast от ByteDance предлага същите възможности като Seedance 2.0 с по-бързи скорости на генериране на по-конкурентна цена.",
|
||||
"doubao-seededit-3-0-i2i-250628.description": "Моделът за изображения на Doubao от ByteDance Seed поддържа вход от текст и изображения с високо контролируемо, висококачествено генериране на изображения. Поддържа редактиране на изображения, водено от текст, с размери на изхода между 512 и 1536 по дългата страна.",
|
||||
"doubao-seedream-3-0-t2i-250415.description": "Seedream 3.0 е модел за генериране на изображения от ByteDance Seed, поддържащ вход от текст и изображения с високо контролируемо, висококачествено генериране на изображения. Генерира изображения от текстови подсказки.",
|
||||
"doubao-seedream-4-0-250828.description": "Seedream 4.0 е модел за генериране на изображения от ByteDance Seed, поддържащ вход от текст и изображения с високо контролируемо, висококачествено генериране на изображения. Генерира изображения от текстови подсказки.",
|
||||
"doubao-seedream-4-5-251128.description": "Seedream 4.5 е най-новият мултимодален модел за изображения на ByteDance, интегриращ текст-към-изображение, изображение-към-изображение и групово генериране на изображения, като включва обща логика и способности за разсъждение. В сравнение с предишната версия 4.0, той предлага значително подобрено качество на генериране, с по-добра консистентност при редактиране и мулти-изображение сливане. Осигурява по-прецизен контрол върху визуалните детайли, като произвежда малък текст и малки лица по-естествено, и постига по-хармонично оформление и цветове, подобрявайки цялостната естетика.",
|
||||
"doubao-seedream-5-0-260128.description": "Doubao-Seedream-5.0-lite е най-новият модел за генериране на изображения на ByteDance. За първи път интегрира възможности за онлайн извличане, позволявайки му да включва информация в реално време от уеб и да подобрява актуалността на генерираните изображения. Интелигентността на модела също е подобрена, позволявайки прецизно интерпретиране на сложни инструкции и визуално съдържание. Освен това предлага подобрено глобално покритие на знания, консистентност на референциите и качество на генериране в професионални сценарии, по-добре отговаряйки на нуждите за визуално създаване на корпоративно ниво.",
|
||||
"dreamina-seedance-2-0-260128.description": "Seedance 2.0 от ByteDance е най-мощният модел за генериране на видео, поддържащ мултимодално генериране на референтно видео, редактиране на видео, разширение на видео, текст-към-видео и изображение-към-видео със синхронизиран звук.",
|
||||
"dreamina-seedance-2-0-fast-260128.description": "Seedance 2.0 Fast от ByteDance предлага същите възможности като Seedance 2.0 с по-бързи скорости на генериране на по-конкурентна цена.",
|
||||
"emohaa.description": "Emohaa е модел за психично здраве с професионални консултантски способности, който помага на потребителите да разберат емоционални проблеми.",
|
||||
"ernie-4.5-0.3b.description": "ERNIE 4.5 0.3B е лек модел с отворен код за локално и персонализирано внедряване.",
|
||||
"ernie-4.5-21b-a3b-thinking.description": "ERNIE-4.5-21B-A3B-Thinking е текстов MoE (смес от експерти) пост-трениран модел с общо 21B параметри и 3B активни параметри, предлагащ значително подобрено качество и дълбочина на разсъждения.",
|
||||
"ernie-4.5-21b-a3b.description": "ERNIE 4.5 21B A3B е модел с отворен код с голям брой параметри и по-силни способности за разбиране и генериране.",
|
||||
"ernie-4.5-300b-a47b.description": "ERNIE 4.5 300B A47B е ултра-голям MoE модел на Baidu ERNIE с отлични способности за разсъждение.",
|
||||
"ernie-4.5-8k-preview.description": "ERNIE 4.5 8K Preview е модел за предварителен преглед с 8K контекст за оценка на ERNIE 4.5.",
|
||||
"ernie-4.5-turbo-128k-preview.description": "Предварителен преглед на ERNIE 4.5 Turbo 128K с възможности на ниво издание, подходящ за интеграция и тестване.",
|
||||
"ernie-4.5-turbo-128k.description": "ERNIE 4.5 Turbo 128K е високопроизводителен общ модел с търсачна поддръжка и извикване на инструменти за QA, програмиране и агентски сценарии.",
|
||||
"ernie-4.5-turbo-20260402.description": "ERNIE 4.5 Turbo 20260402 е високопроизводителен общ модел с добавка за търсене и извикване на инструменти за QA, кодиране и агентни сценарии.",
|
||||
"ernie-4.5-turbo-32k.description": "ERNIE 4.5 Turbo 32K е версия със средна дължина на контекста за QA, извличане от бази знания и многозавойни диалози.",
|
||||
"ernie-4.5-turbo-latest.description": "Най-новият ERNIE 4.5 Turbo с оптимизирана цялостна производителност, идеален за основен продукционен модел.",
|
||||
"ernie-4.5-turbo-vl-32k-preview.description": "ERNIE 4.5 Turbo VL 32K Preview е мултимодален предварителен модел с 32K контекст за оценка на способността за разбиране на дълъг визуален контекст.",
|
||||
"ernie-4.5-turbo-vl-32k.description": "ERNIE 4.5 Turbo VL 32K е мултимодална версия със средно-дълъг контекст за комбинирано разбиране на дълги документи и изображения.",
|
||||
"ernie-4.5-turbo-vl-latest.description": "ERNIE 4.5 Turbo VL Latest е най-новата мултимодална версия с подобрено разбиране и разсъждение върху изображения и текст.",
|
||||
"ernie-4.5-turbo-vl-preview.description": "ERNIE 4.5 Turbo VL Preview е мултимодален предварителен модел за разбиране и генериране на изображения и текст, подходящ за визуални QA и разбиране на съдържание.",
|
||||
"ernie-4.5-turbo-vl.description": "ERNIE 4.5 Turbo VL е зрял мултимодален модел за продукционно разбиране и разпознаване на изображения и текст.",
|
||||
"ernie-4.5-vl-28b-a3b.description": "ERNIE 4.5 VL 28B A3B е мултимодален модел с отворен код за разбиране и разсъждение върху изображения и текст.",
|
||||
"ernie-5.0-thinking-latest.description": "Wenxin 5.0 Thinking е флагмански модел с пълна модалност, обединяващ текст, изображение, аудио и видео. Осигурява значителни подобрения за сложни QA, творчество и агентски сценарии.",
|
||||
"ernie-5.0-thinking-preview.description": "Wenxin 5.0 Thinking Preview е флагмански модел с пълна модалност, обединяващ текст, изображение, аудио и видео. Осигурява значителни подобрения за сложни QA, творчество и агентски сценарии.",
|
||||
"ernie-5.0.description": "ERNIE 5.0 е ново поколение мултимодален модел, който обединява текст, изображения, аудио и видео. Основните му способности са значително подобрени — силен в разбиране, следване на инструкции, творчество, фактическа точност, планиране и работа с инструменти.",
|
||||
"ernie-char-8k.description": "ERNIE Character 8K е модел за диалог с персонажи, предназначен за изграждане на IP персонажи и дългосрочен разговорен спътник.",
|
||||
"ernie-char-fiction-8k-preview.description": "ERNIE Character Fiction 8K Preview е предварителен модел за създаване на персонажи и сюжет, предназначен за оценка и тестване на функции.",
|
||||
"ernie-char-fiction-8k.description": "ERNIE Character Fiction 8K е модел за персонажи, предназначен за романи и създаване на сюжет, подходящ за генериране на дълги истории.",
|
||||
"ernie-image-turbo.description": "ERNIE‑Image е 8B параметъра текст‑към‑изображение модел от Baidu. Води в множество класации, включително първо място в SuperCLUE в Китай.",
|
||||
@@ -548,7 +522,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.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] е модел за генериране на изображения с естетично предпочитание към по-реалистични и естествени изображения.",
|
||||
@@ -556,8 +531,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-kontext-max.description": "Съвременно генериране и редактиране на изображения с контекст, комбиниращо текст и изображения за прецизни и последователни резултати.",
|
||||
@@ -572,7 +547,6 @@
|
||||
"gemini-1.5-flash-001.description": "Gemini 1.5 Flash 001 е ефективен мултимодален модел за мащабиране на приложения.",
|
||||
"gemini-1.5-flash-002.description": "Gemini 1.5 Flash 002 е ефективен мултимодален модел, създаден за широко внедряване.",
|
||||
"gemini-1.5-flash-8b-exp-0924.description": "Gemini 1.5 Flash 8B 0924 е най-новият експериментален модел с значителни подобрения в текстови и мултимодални случаи на употреба.",
|
||||
"gemini-1.5-flash-8b-latest.description": "Gemini 1.5 Flash 8B е ефективен мултимодален модел, създаден за широко внедряване.",
|
||||
"gemini-1.5-flash-8b.description": "Gemini 1.5 Flash 8B е ефективен мултимодален модел за мащабиране на приложения.",
|
||||
"gemini-1.5-flash-exp-0827.description": "Gemini 1.5 Flash 0827 предлага оптимизирана мултимодална обработка за комплексни задачи.",
|
||||
"gemini-1.5-flash-latest.description": "Gemini 1.5 Flash е най-новият мултимодален AI модел на Google с бърза обработка, поддържащ текстови, визуални и видео входове за ефективно мащабиране на задачи.",
|
||||
@@ -588,7 +562,6 @@
|
||||
"gemini-2.5-flash-image.description": "Nano Banana е най-новият, най-бърз и най-ефективен роден мултимодален модел на Google, позволяващ разговорно генериране и редактиране на изображения.",
|
||||
"gemini-2.5-flash-image:image.description": "Nano Banana е най-новият, най-бърз и най-ефективен роден мултимодален модел на Google, позволяващ разговорно генериране и редактиране на изображения.",
|
||||
"gemini-2.5-flash-lite-preview-06-17.description": "Gemini 2.5 Flash-Lite Preview е най-малкият и най-изгоден модел на Google, проектиран за мащабна употреба.",
|
||||
"gemini-2.5-flash-lite-preview-09-2025.description": "Предварителна версия (25 септември 2025 г.) на Gemini 2.5 Flash-Lite",
|
||||
"gemini-2.5-flash-lite.description": "Gemini 2.5 Flash-Lite е най-малкият и най-изгоден модел на Google, проектиран за мащабна употреба.",
|
||||
"gemini-2.5-flash-preview-04-17.description": "Gemini 2.5 Flash Preview е най-изгодният модел на Google с пълни възможности.",
|
||||
"gemini-2.5-flash.description": "Gemini 2.5 Flash е най-изгодният модел на Google с пълни възможности.",
|
||||
@@ -598,16 +571,16 @@
|
||||
"gemini-3-flash-preview.description": "Gemini 3 Flash е най-интелигентният модел, създаден за скорост, съчетаващ авангардна интелигентност с отлично търсене и обоснованост.",
|
||||
"gemini-3-flash.description": "Gemini 3 Flash от Google — ултрабърз модел с мултимодална поддръжка.",
|
||||
"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) — най-бързият нативен модел на Google за генериране на изображения, с поддръжка на разсъждение и редактиране.",
|
||||
"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-3.1-pro.description": "Gemini 3.1 Pro от Google — премиум мултимодален модел с 1M контекст.",
|
||||
"gemini-flash-latest.description": "Най-новата версия на Gemini Flash",
|
||||
"gemini-flash-lite-latest.description": "Най-новата версия на Gemini Flash-Lite",
|
||||
"gemini-pro-latest.description": "Най-новата версия на Gemini Pro",
|
||||
"gemini-flash-latest.description": "Посочва gemini-3-flash-preview",
|
||||
"gemini-flash-lite-latest.description": "Посочва gemini-2.5-flash-lite-preview-09-2025",
|
||||
"gemini-pro-latest.description": "Посочва gemini-3.1-pro-preview",
|
||||
"gemma-7b-it.description": "Gemma 7B е икономически ефективен за малки до средни задачи.",
|
||||
"gemma2-9b-it.description": "Gemma 2 9B е оптимизиран за специфични задачи и интеграция с инструменти.",
|
||||
"gemma2.description": "Gemma 2 е ефективният модел на Google, обхващащ приложения от малки приложения до сложна обработка на данни.",
|
||||
@@ -668,8 +641,6 @@
|
||||
"google/gemini-2.0-flash.description": "Gemini 2.0 Flash е високопроизводителен модел на Google за разширени мултимодални задачи с разсъждение.",
|
||||
"google/gemini-2.5-flash-image.description": "Gemini 2.5 Flash Image (Nano Banana) е модел на Google за генериране на изображения с поддръжка на мултимодален разговор.",
|
||||
"google/gemini-2.5-flash-lite.description": "Gemini 2.5 Flash Lite е олекотен вариант на Gemini 2.5, оптимизиран за ниска латентност и разходи, подходящ за сценарии с висок трафик.",
|
||||
"google/gemini-2.5-flash-preview.description": "Gemini 2.5 Flash е най-усъвършенстваният водещ модел на Google, създаден за напреднало разсъждение, програмиране, математика и научни задачи. Включва вградено „мислене“ за по-точни отговори и по-фино обработване на контекста.\n\nЗабележка: Моделът има два варианта — с мислене и без мислене. Ценообразуването на изхода се различава значително в зависимост от това дали мисленето е активирано. Ако изберете стандартния вариант (без суфикса “:thinking”), моделът изрично ще избягва генериране на мисловни токени.\n\nЗа да използвате мислене и да получавате мисловни токени, трябва да изберете варианта “:thinking”, който има по-висока цена за изхода.\n\nGemini 2.5 Flash може също да бъде конфигуриран чрез параметъра “max reasoning tokens”, както е документирано (https://openrouter.ai/docs/use-cases/reasoning-tokens#max-tokens-for-reasoning).",
|
||||
"google/gemini-2.5-flash-preview:thinking.description": "Gemini 2.5 Flash е най-усъвършенстваният водещ модел на Google, създаден за напреднало разсъждение, програмиране, математика и научни задачи. Включва вградено „мислене“ за по-точни отговори и по-фино обработване на контекста.\n\nЗабележка: Моделът има два варианта — с мислене и без мислене. Ценообразуването на изхода се различава значително в зависимост от това дали мисленето е активирано. Ако изберете стандартния вариант (без суфикса “:thinking”), моделът изрично ще избягва генериране на мисловни токени.\n\nЗа да използвате мислене и да получавате мисловни токени, трябва да изберете варианта “:thinking”, който има по-висока цена за изхода.\n\nGemini 2.5 Flash може също да бъде конфигуриран чрез параметъра “max reasoning tokens”, както е документирано (https://openrouter.ai/docs/use-cases/reasoning-tokens#max-tokens-for-reasoning).",
|
||||
"google/gemini-2.5-flash.description": "Gemini 2.5 Flash е семейство на Google, обхващащо ниска латентност до високопроизводително разсъждение.",
|
||||
"google/gemini-2.5-pro-preview.description": "Gemini 2.5 Pro Preview е най-усъвършенстваният мисловен модел на Google за разсъждение върху сложни проблеми в програмирането, математиката и STEM, както и за анализ на големи набори от данни, кодови бази и документи с дълъг контекст.",
|
||||
"google/gemini-2.5-pro.description": "Gemini 2.5 Pro е водещият модел на Google за разсъждение с поддръжка на дълъг контекст за сложни задачи.",
|
||||
@@ -677,13 +648,10 @@
|
||||
"google/gemini-3-pro-preview.description": "Gemini 3 Pro е модел от ново поколение за мултимодално разсъждение от фамилията Gemini, който разбира текст, аудио, изображения и видео и се справя със сложни задачи и големи кодови бази.",
|
||||
"google/gemini-3.1-flash-image-preview.description": "Gemini 3.1 Flash Image Preview, известен още като \"Nano Banana 2\", е най-новият модел на Google за генериране и редактиране на изображения, предлагащ визуално качество от професионално ниво с Flash скорост. Той комбинира усъвършенствано контекстуално разбиране с бързо, икономично извеждане, правейки сложното генериране на изображения и итеративните редакции значително по-достъпни.",
|
||||
"google/gemini-embedding-001.description": "Модел за вграждане от най-ново поколение с висока производителност при задачи на английски, многоезични и кодови задачи.",
|
||||
"google/gemini-flash-1.5.description": "Gemini 1.5 Flash осигурява оптимизирана мултимодална обработка за широк спектър от сложни задачи.",
|
||||
"google/gemini-pro-1.5.description": "Gemini 1.5 Pro съчетава най-новите оптимизации за по-ефективна обработка на мултимодални данни.",
|
||||
"google/gemma-2-27b-it.description": "Gemma 2 27B е универсален LLM с висока производителност в множество сценарии.",
|
||||
"google/gemma-2-27b.description": "Gemma 2 е ефективна фамилия модели на Google за приложения от малки приложения до сложна обработка на данни.",
|
||||
"google/gemma-2-2b-it.description": "Разширен малък езиков модел, проектиран за edge приложения.",
|
||||
"google/gemma-2-9b-it.description": "Gemma 2 9B, разработен от Google, предлага ефективно следване на инструкции и стабилни общи възможности.",
|
||||
"google/gemma-2-9b-it:free.description": "Gemma 2 е олекотена фамилия модели с отворен код на Google за текст.",
|
||||
"google/gemma-2-9b.description": "Gemma 2 е ефективна фамилия модели на Google за приложения от малки приложения до сложна обработка на данни.",
|
||||
"google/gemma-2b-it.description": "Gemma Instruct (2B) осигурява базова обработка на инструкции за олекотени приложения.",
|
||||
"google/gemma-3-12b-it.description": "Gemma 3 12B е езиков модел с отворен код от Google, който поставя нов стандарт за ефективност и производителност.",
|
||||
@@ -696,13 +664,13 @@
|
||||
"gpt-3.5-turbo.description": "GPT 3.5 Turbo за генериране и разбиране на текст; в момента сочи към gpt-3.5-turbo-0125.",
|
||||
"gpt-35-turbo-16k.description": "GPT-3.5 Turbo 16k е модел за генериране на текст с висока капацитетност за сложни задачи.",
|
||||
"gpt-35-turbo.description": "GPT-3.5 Turbo е ефективният модел на OpenAI за чат и генериране на текст, поддържащ паралелно извикване на функции.",
|
||||
"gpt-4-0125-preview.description": "Най-новият GPT-4 Turbo добавя възможности за визуално разпознаване. Визуалните заявки поддържат JSON режим и извикване на функции. Това е рентабилен мултимодален модел, който балансира точността и ефективността за приложения в реално време.",
|
||||
"gpt-4-0125-preview.description": "Най-новият GPT-4 Turbo модел включва визия. Заявките за визия могат да използват JSON режим и извикване на функции. GPT-4 Turbo е подобрена версия, която балансира точността и ефективността за икономически ефективни мултимодални задачи и взаимодействия в реално време.",
|
||||
"gpt-4-0613.description": "GPT-4 предлага по-голям контекстов прозорец за обработка на по-дълги входове, подходящ за обобщаване на широка информация и анализ на данни.",
|
||||
"gpt-4-1106-preview.description": "Най-новият GPT-4 Turbo добавя възможности за визуално разпознаване. Визуалните заявки поддържат JSON режим и извикване на функции. Това е рентабилен мултимодален модел, който балансира точността и ефективността за приложения в реално време.",
|
||||
"gpt-4-1106-preview.description": "Най-новият GPT-4 Turbo модел включва визия. Заявките за визия могат да използват JSON режим и извикване на функции. GPT-4 Turbo е подобрена версия, която балансира точността и ефективността за икономически ефективни мултимодални задачи и взаимодействия в реално време.",
|
||||
"gpt-4-32k-0613.description": "GPT-4 предлага по-голям контекстов прозорец за обработка на по-дълги входове в сценарии, изискващи интеграция на широка информация и анализ на данни.",
|
||||
"gpt-4-32k.description": "GPT-4 предлага по-голям контекстов прозорец за обработка на по-дълги входове в сценарии, изискващи интеграция на широка информация и анализ на данни.",
|
||||
"gpt-4-turbo-2024-04-09.description": "Най-новият GPT-4 Turbo добавя възможности за визуално разпознаване. Визуалните заявки поддържат JSON режим и извикване на функции. Това е рентабилен мултимодален модел, който балансира точността и ефективността за приложения в реално време.",
|
||||
"gpt-4-turbo-preview.description": "Най-новият GPT-4 Turbo добавя възможности за визуално разпознаване. Визуалните заявки поддържат JSON режим и извикване на функции. Това е рентабилен мултимодален модел, който балансира точността и ефективността за приложения в реално време.",
|
||||
"gpt-4-turbo-preview.description": "Най-новият GPT-4 Turbo модел включва визия. Заявките за визия могат да използват JSON режим и извикване на функции. GPT-4 Turbo е подобрена версия, която балансира точността и ефективността за икономически ефективни мултимодални задачи и взаимодействия в реално време.",
|
||||
"gpt-4-turbo.description": "Най-новият GPT-4 Turbo добавя възможности за визуално разпознаване. Визуалните заявки поддържат JSON режим и извикване на функции. Това е рентабилен мултимодален модел, който балансира точността и ефективността за приложения в реално време.",
|
||||
"gpt-4-vision-preview.description": "Предварителен преглед на GPT-4 Vision, създаден за задачи по анализ и обработка на изображения.",
|
||||
"gpt-4.1-mini.description": "GPT-4.1 mini балансира интелигентност, скорост и цена, което го прави привлекателен за множество приложения.",
|
||||
@@ -749,7 +717,7 @@
|
||||
"gpt-5.4-pro.description": "GPT‑5.4 Pro от OpenAI — най-способният модел с максимален контекст и разсъждение.",
|
||||
"gpt-5.4.description": "GPT‑5.4 от OpenAI — следващо поколение модел с 1M+ контекст и мултимодален вход.",
|
||||
"gpt-5.5-pro.description": "GPT‑5.5 Pro използва повече изчисления, за да разсъждава по-дълбоко и да дава по-точни отговори.",
|
||||
"gpt-5.5.description": "GPT‑5.5 е водещ модел за най-сложната професионална работа, кодиране и агентни задачи.",
|
||||
"gpt-5.5.description": "GPT-5.5 е нашият най-нов модел за най-сложната професионална работа.",
|
||||
"gpt-5.description": "GPT‑5 от OpenAI — флагмански модел с усъвършенствано разсъждение и мултимодалност.",
|
||||
"gpt-audio.description": "GPT Audio е универсален чат модел за вход/изход на аудио, поддържан в Chat Completions API.",
|
||||
"gpt-image-1-mini.description": "По-евтин вариант на GPT Image 1 с роден вход от текст и изображения и изход на изображения.",
|
||||
@@ -772,8 +740,11 @@
|
||||
"grok-4-fast-reasoning.description": "С гордост представяме Grok 4 Fast – нашият най-нов напредък в икономичните логически модели.",
|
||||
"grok-4.20-0309-non-reasoning.description": "Неразсъждаващ вариант за прости случаи.",
|
||||
"grok-4.20-0309-reasoning.description": "Интелигентен, изключително бърз модел с разсъждение.",
|
||||
"grok-4.20-beta-0309-non-reasoning.description": "Вариант без разсъждения за прости случаи на употреба",
|
||||
"grok-4.20-beta-0309-reasoning.description": "Интелигентен, изключително бърз модел, който разсъждава преди да отговори",
|
||||
"grok-4.20-multi-agent-0309.description": "Екип от 4 или 16 агента — отличен за проучвания; поддържа само xAI сървърни инструменти.",
|
||||
"grok-4.description": "Последният флагман Grok с ненадминати способности в език, математика и разсъждение. Насочва към grok‑4‑0709; временно с 10% по-висока цена.",
|
||||
"grok-4.3.description": "Най-истинно търсещият голям езиков модел в света",
|
||||
"grok-4.description": "Нашият най-нов и най-силен флагмански модел, отличаващ се в NLP, математика и разсъждения — идеален универсален инструмент.",
|
||||
"grok-code-fast-1.description": "С гордост представяме grok-code-fast-1 – бърз и икономичен логически модел, който се отличава в агентско програмиране.",
|
||||
"grok-imagine-image-pro.description": "Генерирайте изображения от текстови подсказки, редактирайте съществуващи изображения с естествен език или итеративно усъвършенствайте изображения чрез многократни разговори.",
|
||||
"grok-imagine-image.description": "Генерирайте изображения от текстови подсказки, редактирайте съществуващи изображения с естествен език или итеративно усъвършенствайте изображения чрез многократни разговори.",
|
||||
@@ -820,7 +791,6 @@
|
||||
"intern-s1-mini.description": "Лек мултимодален голям модел със силни научни способности за разсъждение.",
|
||||
"intern-s1-pro.description": "Пуснахме най-напредналия ни отворен мултимодален модел за разсъждение, в момента най-добре представящият се отворен мултимодален голям езиков модел по отношение на общата производителност.",
|
||||
"intern-s1.description": "Отвореният мултимодален модел за разсъждение не само демонстрира силни общи способности, но и постига най-добри резултати в широк спектър от научни задачи.",
|
||||
"internlm/internlm2_5-7b-chat.description": "InternLM2.5-7B-Chat е отворен модел за чат, базиран на архитектурата InternLM2. Моделът с 7B параметри е фокусиран върху генериране на диалог с поддръжка на китайски/английски, използвайки съвременно обучение за плавен и интелигентен разговор. Подходящ е за различни сценарии като клиентска поддръжка и лични асистенти.",
|
||||
"internvl2.5-38b-mpo.description": "InternVL2.5 38B MPO е мултимодален предварително обучен модел за комплексно визуално-текстово разсъждение.",
|
||||
"internvl3-14b.description": "InternVL3 14B е среден по размер мултимодален модел, балансиращ между производителност и разходи.",
|
||||
"internvl3-1b.description": "InternVL3 1B е лек мултимодален модел за внедряване при ограничени ресурси.",
|
||||
@@ -835,11 +805,10 @@
|
||||
"kimi-k2-0905-preview.description": "kimi-k2-0905-preview предлага прозорец на контекста от 256k, по-силно агентно програмиране, по-добро качество на front-end код и подобрено разбиране на контекста.",
|
||||
"kimi-k2-instruct.description": "Kimi K2 Instruct е официалният модел за разсъждение на Kimi с дълъг контекст за код, въпроси и отговори и други.",
|
||||
"kimi-k2-thinking-turbo.description": "Високоскоростен вариант на K2 с дълбоко мислене, 256k контекст, силно дълбоко разсъждение и скорост на изход от 60–100 токена/сек.",
|
||||
"kimi-k2-thinking.description": "Kimi-K2 е основен модел с архитектура MoE, пуснат от Moonshot AI, с изключително силни способности за кодиране и агенти. Той има общо 1T параметри и 32B активни параметри. В тестове за производителност в основни категории като общо знание, разсъждение, програмиране, математика и агенти, производителността на модела K2 надминава тази на други основни модели с отворен код.",
|
||||
"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.6.description": "Kimi K2.6 — най-способният модел на Kimi, с подобрено кодиране, инструкции и самокорекция; поддържа текст, изображения и видео.",
|
||||
"kimi-k2.description": "Kimi-K2 е MoE базов модел от Moonshot AI с мощни способности за програмиране и агентни задачи, с общо 1T параметри и 32B активни. В бенчмаркове за общо разсъждение, програмиране, математика и агентни задачи надминава други водещи отворени модели.",
|
||||
"kimi-k2.6.description": "Kimi-K2.6 е голям езиков модел, стартиран от Moonshot AI, с отлични възможности за кодиране и извикване на инструменти. Услугата се поддържа само в континентален Китай.",
|
||||
"kimi-k2:1t.description": "Kimi K2 е голям MoE LLM от Moonshot AI с 1T общи параметри и 32B активни на всяко преминаване. Оптимизиран е за агентни способности, включително напреднало използване на инструменти, разсъждение и синтез на код.",
|
||||
"kling/kling-v3-image-generation.description": "Поддържа до 10 референтни изображения, позволявайки заключване на обекти, елементи и цветови тонове за осигуряване на консистентен стил. Комбинира трансфер на стил, референция на портрети/персонажи, сливане на множество изображения и локализирано инпейнтинг за гъвкав контрол. Осигурява реалистични детайли на портрети, с обща визуализация, която е деликатна и богато наситена, с кинематографични цветове и атмосфера.",
|
||||
"kling/kling-v3-omni-image-generation.description": "Отключете кинематографични визуализации за разказване на истории с ново поколение генериране на изображения и директен изход в 2K/4K. Дълбоко анализира аудиовизуалните елементи в подсказките, за да изпълни прецизно творческите инструкции. Поддържа гъвкави мултиреферентни входове и цялостни подобрения в качеството, идеални за сторибордове, концептуално изкуство за разказване на истории и дизайн на сцени.",
|
||||
@@ -904,7 +873,6 @@
|
||||
"meta-llama/llama-3-8b-instruct.description": "Llama 3 8B Instruct е оптимизиран за висококачествени диалози, превъзхождайки много затворени модели.",
|
||||
"meta-llama/llama-3.1-70b-instruct.description": "Най-новата серия Llama 3.1 на Meta, 70B вариант, обучен с инструкции, оптимизиран за висококачествени диалози. В индустриални оценки показва силна производителност спрямо водещи затворени модели. (Достъпен само за потвърдени бизнес потребители.)",
|
||||
"meta-llama/llama-3.1-8b-instruct.description": "Най-новата серия Llama 3.1 на Meta, 8B вариант, обучен с инструкции, е особено бърз и ефективен. В индустриални оценки показва силна производителност, надминавайки много водещи затворени модели. (Достъпен само за потвърдени бизнес потребители.)",
|
||||
"meta-llama/llama-3.1-8b-instruct:free.description": "LLaMA 3.1 предлага многоезична поддръжка и е сред водещите генеративни модели.",
|
||||
"meta-llama/llama-3.2-11b-vision-instruct.description": "LLaMA 3.2 е създаден за задачи, съчетаващи визия и текст. Отличава се в описване на изображения и визуални въпроси, свързвайки езиковото генериране с визуалното разсъждение.",
|
||||
"meta-llama/llama-3.2-3b-instruct.description": "meta-llama/llama-3.2-3b-instruct",
|
||||
"meta-llama/llama-3.3-70b-instruct.description": "Llama 3.3 е най-усъвършенстваният многоезичен отворен модел от серията Llama, предлагащ производителност, близка до 405B, на много ниска цена. Базиран е на Transformer архитектура и подобрен чрез SFT и RLHF за полезност и безопасност. Версията, обучена с инструкции, е оптимизирана за многоезичен чат и превъзхожда много отворени и затворени модели в индустриалните бенчмаркове. Край на знанията: декември 2023.",
|
||||
@@ -922,7 +890,6 @@
|
||||
"meta/Meta-Llama-3.1-405B-Instruct.description": "Llama 3.1, настроен за инструкции, е текстов модел, оптимизиран за многоезичен чат, с висока производителност в индустриалните бенчмаркове сред отворени и затворени модели.",
|
||||
"meta/Meta-Llama-3.1-70B-Instruct.description": "Llama 3.1, настроен за инструкции, е текстов модел, оптимизиран за многоезичен чат, с висока производителност в индустриалните бенчмаркове сред отворени и затворени модели.",
|
||||
"meta/Meta-Llama-3.1-8B-Instruct.description": "Llama 3.1, настроен за инструкции, е текстов модел, оптимизиран за многоезичен чат, с висока производителност в индустриалните бенчмаркове сред отворени и затворени модели.",
|
||||
"meta/llama-3.1-405b-instruct.description": "Разширен LLM, поддържащ генериране на синтетични данни, дистилация на знания и логическо мислене за чатботи, програмиране и специализирани задачи.",
|
||||
"meta/llama-3.1-70b-instruct.description": "Създаден за сложни диалози с отлично разбиране на контекста, логическо мислене и генериране на текст.",
|
||||
"meta/llama-3.1-70b.description": "Обновен Meta Llama 3 70B Instruct с 128K контекст, многоезична поддръжка и подобрено логическо мислене.",
|
||||
"meta/llama-3.1-8b-instruct.description": "Модерен модел с високо ниво на езиково разбиране, логическо мислене и генериране на текст.",
|
||||
@@ -962,7 +929,6 @@
|
||||
"minimax-m2.description": "MiniMax M2 е ефективен голям езиков модел, създаден специално за програмиране и агентни работни потоци.",
|
||||
"minimax/minimax-m2.1.description": "MiniMax-M2.1 е лек, авангарден голям езиков модел, оптимизиран за програмиране, агентни работни потоци и съвременно разработване на приложения, осигуряващ по-чист, по-кратък изход и по-бърза реакция.",
|
||||
"minimax/minimax-m2.description": "MiniMax-M2 е високостойностен модел, който се отличава в програмиране и агентни задачи в множество инженерни сценарии.",
|
||||
"minimaxai/minimax-m2.5.description": "MiniMax-M2.5 е най-новият голям езиков модел от MiniMax, с архитектура Mixture-of-Experts (MoE) и общо 229 милиарда параметри. Той постига водеща в индустрията производителност в програмиране, извикване на инструменти от агенти, задачи за търсене и офис сценарии.",
|
||||
"ministral-3:14b.description": "Ministral 3 14B е най-големият модел в серията Ministral 3, предлагащ производителност от най-високо ниво, сравнима с по-големия си еквивалент Mistral Small 3.2 24B. Оптимизиран за локално внедряване, той предлага висока производителност на различен хардуер, включително локални настройки.",
|
||||
"ministral-3:3b.description": "Ministral 3 3B е най-малкият и най-ефективен модел в серията Ministral 3, предлагащ силни езикови и визуални способности в компактна опаковка. Предназначен за внедряване на периферията, той предлага висока производителност на различен хардуер, включително локални настройки.",
|
||||
"ministral-3:8b.description": "Ministral 3 8B е мощен и ефективен модел в серията Ministral 3, предлагащ текстови и визуални способности от най-високо ниво. Създаден за внедряване на периферията, той предлага висока производителност на различен хардуер, включително локални настройки.",
|
||||
@@ -978,6 +944,7 @@
|
||||
"mistral-large-latest.description": "Mistral Large е водещият модел, отличаващ се в многоезични задачи, сложни разсъждения и генериране на код за приложения от висок клас.",
|
||||
"mistral-large.description": "Mixtral Large е флагманският модел на Mistral, комбиниращ генериране на код, математика и разсъждение с 128K контекстен прозорец.",
|
||||
"mistral-medium-2508.description": "Mistral Medium 3.1 предлага производителност от най-високо ниво при 8× по-ниска цена и опростява внедряването в предприятия.",
|
||||
"mistral-medium-3.5.description": "Mistral Medium 3.5 е модел от клас frontier, оптимизиран за мултимодални и кодиращи случаи на употреба, пуснат с отворени тегла под модифициран MIT лиценз.",
|
||||
"mistral-nemo-instruct.description": "Mistral-Nemo-Instruct-2407 е версия, настроена за инструкции, на Mistral-Nemo-Base-2407.",
|
||||
"mistral-nemo.description": "Mistral Nemo е високоефективен 12B модел от Mistral AI и NVIDIA.",
|
||||
"mistral-small-2506.description": "Mistral Small е икономичен, бърз и надежден вариант за превод, обобщение и анализ на настроения.",
|
||||
@@ -1020,7 +987,6 @@
|
||||
"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, подходящ за висококачествен код и използване на инструменти.",
|
||||
"moonshotai/kimi-k2-0905.description": "Kimi K2 0905 е актуализация, която разширява контекста и логическата производителност с оптимизации за програмиране.",
|
||||
"moonshotai/kimi-k2-instruct-0905.description": "Моделът kimi-k2-0905-preview поддържа 256K контекстен прозорец, с по-силно агентно програмиране, по-изпипан и практичен фронтенд код и по-добро разбиране на контекста.",
|
||||
"moonshotai/kimi-k2-thinking-turbo.description": "Kimi K2 Thinking Turbo е високоскоростна версия на Kimi K2 Thinking, значително намаляваща латентността, като запазва дълбокото разсъждение.",
|
||||
"moonshotai/kimi-k2-thinking.description": "Kimi K2 Thinking е модел за разсъждение на Moonshot, оптимизиран за задачи, изискващи дълбоко мислене, с общи агентни способности.",
|
||||
"moonshotai/kimi-k2.5.description": "Kimi K2.5 е най-интелигентният модел Kimi досега, с вградена мултимодална архитектура.",
|
||||
@@ -1079,7 +1045,7 @@
|
||||
"openai/gpt-5.description": "GPT-5 е високоефективният модел на OpenAI за широк спектър от производствени и изследователски задачи.",
|
||||
"openai/gpt-oss-120b.description": "Много способен универсален LLM с силно и контролируемо разсъждение.",
|
||||
"openai/gpt-oss-20b.description": "Компактен езиков модел с отворени тегла, оптимизиран за ниска латентност и среди с ограничени ресурси, включително локални и edge внедрявания.",
|
||||
"openai/o1-mini.description": "o1-mini е бърз, икономичен модел за разсъждение, проектиран за програмиране, математика и наука. Има контекст от 128K и граница на знанията от октомври 2023 г.",
|
||||
"openai/o1-mini.description": "o1-mini е бърз, икономически ефективен модел за разсъждения, проектиран за кодиране, математика и научни случаи на употреба. Има 128K контекст и октомври 2023 като краен срок за знания.",
|
||||
"openai/o1-preview.description": "o1 е новият модел за разсъждение на OpenAI за сложни задачи, изискващи широка обща култура. Има контекст от 128K и граница на знанията от октомври 2023 г.",
|
||||
"openai/o1.description": "OpenAI o1 е водещ модел за разсъждение, създаден за сложни проблеми, изискващи дълбоко мислене, предоставящ силно разсъждение и по-висока точност при многoетапни задачи.",
|
||||
"openai/o3-mini-high.description": "o3-mini (високо разсъждение) предлага по-висок интелект при същите цели за цена и латентност като o1-mini.",
|
||||
@@ -1123,7 +1089,6 @@
|
||||
"qianfan-check-vl.description": "Qianfan Check VL е мултимодален модел за преглед на съдържание, съвместимост между изображение и текст и задачи по разпознаване.",
|
||||
"qianfan-composition.description": "Qianfan Composition е мултимодален модел за създаване, разбиране и генериране на смесено изображение и текст.",
|
||||
"qianfan-engcard-vl.description": "Qianfan EngCard VL е мултимодален модел за разпознаване, фокусиран върху английски езикови сценарии.",
|
||||
"qianfan-llama-vl-8b.description": "Qianfan Llama VL 8B е мултимодален модел, базиран на Llama, за общо разбиране на изображения и текст.",
|
||||
"qianfan-multipicocr.description": "Qianfan MultiPicOCR е OCR модел за множество изображения, откриващ и разпознаващ текст в различни изображения.",
|
||||
"qianfan-qi-vl.description": "Qianfan QI VL е мултимодален модел за въпроси и отговори с точна извличане и отговори в сложни сценарии с изображения и текст.",
|
||||
"qianfan-singlepicocr.description": "Qianfan SinglePicOCR е OCR модел за едно изображение с висока точност при разпознаване на символи.",
|
||||
@@ -1162,7 +1127,6 @@
|
||||
"qwen-vl-plus.description": "Подобрен голям мултимодален модел от серията Qwen с значителни подобрения в детайлите и разпознаването на текст, поддържащ резолюция над 1 мегапиксел и произволни съотношения.",
|
||||
"qwen-vl-v1.description": "Предварително обучен модел, инициализиран от Qwen-7B с добавен визуален модул и вход за изображения с резолюция 448.",
|
||||
"qwen/qwen-2-7b-instruct.description": "Qwen2 е новата серия LLM модели Qwen. Qwen2 7B е трансформаторен модел, който се отличава с езиково разбиране, многоезичност, програмиране, математика и логическо мислене.",
|
||||
"qwen/qwen-2-7b-instruct:free.description": "Qwen2 е ново семейство големи езикови модели с по-силни способности за разбиране и генериране.",
|
||||
"qwen/qwen-2-vl-72b-instruct.description": "Qwen2-VL е най-новата версия на Qwen-VL, постигайки водещи резултати в бенчмаркове за визуално разбиране като MathVista, DocVQA, RealWorldQA и MTVQA. Може да разбира видео с продължителност над 20 минути за висококачествени въпроси и отговори, диалог и създаване на съдържание. Справя се с комплексно разсъждение и вземане на решения, интегрирайки се с мобилни устройства и роботи за действия въз основа на визуален контекст и текстови инструкции. Освен английски и китайски, чете текст в изображения на много езици, включително повечето европейски езици, японски, корейски, арабски и виетнамски.",
|
||||
"qwen/qwen-2.5-72b-instruct.description": "Qwen2.5-72B-Instruct е един от най-новите LLM модели на Alibaba Cloud. Моделът с 72 милиарда параметъра предлага значителни подобрения в програмирането и математиката, поддържа над 29 езика (включително китайски и английски) и значително подобрява следването на инструкции, разбирането на структурирани данни и генерирането на структурирани изходи (особено JSON).",
|
||||
"qwen/qwen2.5-32b-instruct.description": "Qwen2.5-32B-Instruct е един от най-новите LLM модели на Alibaba Cloud. Моделът с 32 милиарда параметъра предлага значителни подобрения в програмирането и математиката, поддържа над 29 езика (включително китайски и английски) и значително подобрява следването на инструкции, разбирането на структурирани данни и генерирането на структурирани изходи (особено JSON).",
|
||||
@@ -1170,16 +1134,11 @@
|
||||
"qwen/qwen2.5-coder-32b-instruct.description": "Разширен LLM модел за генериране, анализ и корекция на код на основните програмни езици.",
|
||||
"qwen/qwen2.5-coder-7b-instruct.description": "Силен среден по размер модел за програмиране с 32K контекст, отличаващ се в многоезично програмиране.",
|
||||
"qwen/qwen3-14b.description": "Qwen3-14B е 14-милиарден вариант за общо разсъждение и чат сценарии.",
|
||||
"qwen/qwen3-14b:free.description": "Qwen3-14B е плътен LLM модел с 14.8 милиарда параметъра, създаден за сложни разсъждения и ефективен чат. Превключва между режим на мислене за математика, програмиране и логика и режим без мислене за общ чат. Фино настроен за следване на инструкции, използване на инструменти и творческо писане на над 100 езика и диалекта. Поддържа 32K контекст по подразбиране и се мащабира до 131K с YaRN.",
|
||||
"qwen/qwen3-235b-a22b-2507.description": "Qwen3-235B-A22B-Instruct-2507 е вариантът Instruct от серията Qwen3, балансиращ между многоезично използване на инструкции и сценарии с дълъг контекст.",
|
||||
"qwen/qwen3-235b-a22b-thinking-2507.description": "Qwen3-235B-A22B-Thinking-2507 е вариантът Thinking от Qwen3, подсилен за сложни математически и логически задачи.",
|
||||
"qwen/qwen3-235b-a22b.description": "Qwen3-235B-A22B е MoE модел с 235 милиарда параметъра от Qwen, с 22 милиарда активни при всяко преминаване. Превключва между режим на мислене за сложни разсъждения, математика и код и режим без мислене за ефективен чат. Предлага силно разсъждение, многоезична поддръжка (над 100 езика/диалекта), напреднало следване на инструкции и използване на инструменти. Поддържа 32K контекст по подразбиране и се мащабира до 131K с YaRN.",
|
||||
"qwen/qwen3-235b-a22b:free.description": "Qwen3-235B-A22B е MoE модел с 235 милиарда параметъра от Qwen, с 22 милиарда активни при всяко преминаване. Превключва между режим на мислене за сложни разсъждения, математика и код и режим без мислене за ефективен чат. Предлага силно разсъждение, многоезична поддръжка (над 100 езика/диалекта), напреднало следване на инструкции и използване на инструменти. Поддържа 32K контекст по подразбиране и се мащабира до 131K с YaRN.",
|
||||
"qwen/qwen3-30b-a3b.description": "Qwen3 е най-новото поколение LLM модели от Qwen с плътни и MoE архитектури, отличаващи се в разсъждение, многоезична поддръжка и напреднали агентски задачи. Уникалната му способност да превключва между режим на мислене за сложни задачи и режим без мислене за ефективен чат осигурява гъвкава и висококачествена производителност.\n\nQwen3 значително превъзхожда предишни модели като QwQ и Qwen2.5, предоставяйки отлични резултати в математика, програмиране, логическо мислене, творческо писане и интерактивен чат. Вариантът Qwen3-30B-A3B има 30.5 милиарда параметъра (3.3 милиарда активни), 48 слоя, 128 експерта (8 активни на задача) и поддържа до 131K контекст с YaRN, поставяйки нов стандарт за отворени модели.",
|
||||
"qwen/qwen3-30b-a3b:free.description": "Qwen3 е най-новото поколение LLM модели от Qwen с плътни и MoE архитектури, отличаващи се в разсъждение, многоезична поддръжка и напреднали агентски задачи. Уникалната му способност да превключва между режим на мислене за сложни задачи и режим без мислене за ефективен чат осигурява гъвкава и висококачествена производителност.\n\nQwen3 значително превъзхожда предишни модели като QwQ и Qwen2.5, предоставяйки отлични резултати в математика, програмиране, логическо мислене, творческо писане и интерактивен чат. Вариантът Qwen3-30B-A3B има 30.5 милиарда параметъра (3.3 милиарда активни), 48 слоя, 128 експерта (8 активни на задача) и поддържа до 131K контекст с YaRN, поставяйки нов стандарт за отворени модели.",
|
||||
"qwen/qwen3-32b.description": "Qwen3-32B е плътен LLM модел с 32.8 милиарда параметъра, оптимизиран за сложни разсъждения и ефективен чат. Превключва между режим на мислене за математика, програмиране и логика и режим без мислене за по-бърз общ чат. Отличава се в следване на инструкции, използване на инструменти и творческо писане на над 100 езика и диалекта. Поддържа 32K контекст по подразбиране и се мащабира до 131K с YaRN.",
|
||||
"qwen/qwen3-32b:free.description": "Qwen3-32B е плътен LLM модел с 32.8 милиарда параметъра, оптимизиран за сложни разсъждения и ефективен чат. Превключва между режим на мислене за математика, програмиране и логика и режим без мислене за по-бърз общ чат. Отличава се в следване на инструкции, използване на инструменти и творческо писане на над 100 езика и диалекта. Поддържа 32K контекст по подразбиране и се мащабира до 131K с YaRN.",
|
||||
"qwen/qwen3-8b:free.description": "Qwen3-8B е плътен LLM модел с 8.2 милиарда параметъра, създаден за задачи, изискващи разсъждение, и ефективен чат. Превключва между режим на мислене за математика, програмиране и логика и режим без мислене за общ чат. Фино настроен за следване на инструкции, интеграция с агенти и творческо писане на над 100 езика и диалекта. Поддържа 32K контекст по подразбиране и се мащабира до 131K с YaRN.",
|
||||
"qwen/qwen3-coder-plus.description": "Qwen3-Coder-Plus е модел от серията Qwen, оптимизиран за по-сложно използване на инструменти и дълготрайни сесии.",
|
||||
"qwen/qwen3-coder.description": "Qwen3-Coder е част от семейството за генериране на код Qwen3, силен в разбирането и създаването на код от дълги документи.",
|
||||
"qwen/qwen3-max-preview.description": "Qwen3 Max (преглед) е вариантът Max за напреднало разсъждение и интеграция с инструменти.",
|
||||
@@ -1195,7 +1154,7 @@
|
||||
"qwen2.5-14b-instruct.description": "Qwen2.5 отворен код, модел с 14B параметъра.",
|
||||
"qwen2.5-32b-instruct.description": "Qwen2.5 отворен код, модел с 32B параметъра.",
|
||||
"qwen2.5-72b-instruct.description": "Qwen2.5 отворен код, модел с 72B параметъра.",
|
||||
"qwen2.5-7b-instruct.description": "Qwen2.5 7B Instruct е зрял модел с отворен код за чат и генериране в различни сценарии.",
|
||||
"qwen2.5-7b-instruct.description": "Qwen2.5 отворен модел с 7B параметри.",
|
||||
"qwen2.5-coder-1.5b-instruct.description": "Модел за програмиране Qwen с отворен код.",
|
||||
"qwen2.5-coder-14b-instruct.description": "Модел за програмиране Qwen с отворен код.",
|
||||
"qwen2.5-coder-32b-instruct.description": "Модел за програмиране Qwen с отворен код.",
|
||||
@@ -1208,7 +1167,7 @@
|
||||
"qwen2.5-omni-7b.description": "Моделите Qwen-Omni поддържат мултимодални входове (видео, аудио, изображения, текст) и извеждат аудио и текст.",
|
||||
"qwen2.5-vl-32b-instruct.description": "Qwen2.5 VL 32B Instruct е мултимодален модел с отворен код, подходящ за частно внедряване и използване в различни сценарии.",
|
||||
"qwen2.5-vl-72b-instruct.description": "Подобрен следване на инструкции, математика, решаване на задачи и програмиране, с по-силно разпознаване на обекти. Поддържа точно локализиране на визуални елементи във всички формати, разбиране на дълги видеа (до 10 минути) с прецизно времево маркиране, разбиране на последователност и скорост, както и агенти, които могат да управляват ОС или мобилни устройства чрез парсинг и локализация. Силен в извличането на ключова информация и изход в JSON формат. Това е най-мощната версия от серията с 72B параметъра.",
|
||||
"qwen2.5-vl-7b-instruct.description": "Qwen2.5 VL 7B Instruct е лек мултимодален модел, балансиращ между разходи за внедряване и способности за разпознаване.",
|
||||
"qwen2.5-vl-7b-instruct.description": "Подобрено следване на инструкции, математика, решаване на проблеми и кодиране, със силно разпознаване на обекти. Поддържа прецизно локализиране на визуални елементи във формати, дълго разбиране на видео (до 10 минути) с времево подреждане на събития, разбиране на скорост и агенти, които могат да контролират ОС или мобилни устройства чрез парсинг и локализация. Силно извличане на ключова информация и JSON изход. Това е най-силната версия в серията с 72B параметри.",
|
||||
"qwen2.5-vl-instruct.description": "Qwen2.5-VL е най-новият модел за визия и език от семейството Qwen.",
|
||||
"qwen2.5.description": "Qwen2.5 е следващото поколение голям езиков модел на Alibaba с висока производителност в различни приложения.",
|
||||
"qwen2.5:0.5b.description": "Qwen2.5 е следващото поколение голям езиков модел на Alibaba с висока производителност в различни приложения.",
|
||||
@@ -1262,7 +1221,7 @@
|
||||
"qwen3.5-plus-2026-04-20.description": "Qwen 3.5 — мултимодален Plus модел с подобрено агентно кодиране, висока скорост и силно разсъждение. Снимка от 20 април 2026.",
|
||||
"qwen3.5-plus.description": "Qwen3.5 Plus поддържа текст, изображения и видео вход. Производителността му при чисто текстови задачи е сравнима с Qwen3 Max, с по-добра производителност и по-ниска цена. Мултимодалните му възможности са значително подобрени в сравнение със серията Qwen3 VL.",
|
||||
"qwen3.5:397b.description": "Qwen3.5 е обединен модел за визия и език с хибридна архитектура (Mixture-of-Experts + линейно внимание), предлагащ силни мултимодални разсъждения, кодиране и способности за дълъг контекст с 256K контекстен прозорец.",
|
||||
"qwen3.6-27b.description": "Qwen 3.6 27B — плътен визия‑език модел с значително по‑силни агентни и STEM способности, както и подобрено видео и документно разбиране.",
|
||||
"qwen3.6-27b.description": "Qwen3.6 27B е отворен плътен модел с висока производителност в разсъждения, кодиране и общи способности. Поддържа мисловен режим по подразбиране, предлагайки балансирана производителност и ефективност.",
|
||||
"qwen3.6-35b-a3b.description": "Нативният vision-language модел Qwen3.6 35B-A3B е изграден върху хибридна архитектура, която интегрира механизъм за линейно внимание със спорадичен Mixture-of-Experts (MoE) дизайн, постигащ по-висока ефективност при инфериране. В сравнение с модела 3.5-35B-A3B предоставя значителни подобрения в агентското програмиране, математическото разсъждение, разсъжденията върху код, пространствения интелект, както и в локализацията на обекти и откриването на цели.",
|
||||
"qwen3.6-flash.description": "Нативният vision-language модел Qwen3.6 Flash предоставя значително подобрено представяне в сравнение с версия 3.5-Flash. Този модел се фокусира върху повишаване на възможностите за агентско програмиране (значително превъзхожда предшественика си в множество стандартизирани тестове за код-агенти), както и подобрения в математическото и кодовото разсъждение. В областта на визуалните задачи демонстрира съществени подобрения в пространствения интелект, със силно повишена точност в локализацията на обекти и откриването на цели.",
|
||||
"qwen3.6-max-preview.description": "Най-големият модел със затворен код в серията Qwen3.6. Предоставя по-силни знания за света, по-добро следване на инструкции и агентско програмиране за комплексни задачи. Той е само текстов, поддържа мислещ режим по подразбиране, explicit caching и извикване на функции.",
|
||||
@@ -1274,6 +1233,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 предлага генериране, обогатено с уеб търсене за реална информация, подобрено тълкуване на сложни подсказки и подобрена консистентност на референциите за професионално визуално създаване.",
|
||||
"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 с разширена езикова поддръжка и по-дълъг контекст.",
|
||||
@@ -1308,6 +1269,7 @@
|
||||
"step-3.5-flash-2603.description": "Базиран на Step 3.5 Flash, оптимизиран за агентни сценарии, с по-добра ефективност на токени, по-бърза инференция и режим с ниско разсъждение.",
|
||||
"step-3.5-flash.description": "Флагманският модел за езиково разсъждение на Stepfun. Този модел има първокласни способности за разсъждение и бързи и надеждни изпълнителни възможности. Може да разлага и планира сложни задачи, бързо и надеждно да извиква инструменти за изпълнение на задачи и да бъде компетентен в различни сложни задачи като логическо разсъждение, математика, софтуерно инженерство и задълбочени изследвания.",
|
||||
"step-3.description": "Този модел притежава силно визуално възприятие и сложна логика, точно обработва междудомейново знание, анализ между математика и визия и широк спектър от ежедневни визуални задачи.",
|
||||
"step-image-edit-2.description": "Лек модел за редактиране от последната итерация на Stepfun, който поддържа както генериране на изображения от текст, така и редактиране на изображения в един модел. Въпреки че има по-малко от 6 милиарда параметри, той постига водещи резултати за своя мащаб, съперничейки на отворени модели в диапазона 12B–20B параметри. Всяка задача за редактиране отнема само 1–2 секунди, преосмисляйки изживяването на редактиране на изображения в реално време.",
|
||||
"step-r1-v-mini.description": "Модел за логическо разсъждение със силно визуално разбиране, който може да обработва изображения и текст, след което да генерира текст след дълбоко разсъждение. Отличава се във визуално разсъждение и предоставя водещи резултати в математика, програмиране и текстово разсъждение, с контекстен прозорец от 100K.",
|
||||
"stepfun-ai/step3.description": "Step3 е авангарден модел за мултимодално разсъждение от StepFun, построен върху архитектура MoE с 321 милиарда общи и 38 милиарда активни параметри. Неговият дизайн от край до край минимизира разходите за декодиране, като същевременно осигурява водещо разсъждение за визия и език. С дизайна MFA и AFD, той остава ефективен както на водещи, така и на нискобюджетни ускорители. Предварителното обучение използва над 20 трилиона текстови токени и 4 трилиона токени за изображения-текстове на много езици. Той достига водещи резултати сред модели с отворен код в математика, код и мултимодални бенчмаркове.",
|
||||
"taichu4_vl_2b_nothinking.description": "Версията без мислене на модела Taichu4.0-VL 2B се отличава с по-ниска употреба на памет, лек дизайн, бърза скорост на отговор и силни способности за мултимодално разбиране.",
|
||||
@@ -1323,11 +1285,7 @@
|
||||
"text-embedding-3-large.description": "Най-способният модел за вграждане за задачи на английски и други езици.",
|
||||
"text-embedding-3-small.description": "Ефективен, икономичен модел от ново поколение за вграждане, подходящ за извличане и RAG сценарии.",
|
||||
"thudm/glm-4-32b.description": "GLM-4-32B-0414 е двуезичен (китайски/английски) модел с отворени тегла и 32B параметъра, оптимизиран за генериране на код, извикване на функции и агентни задачи. Предобучен върху 15T висококачествени и логически наситени данни и допълнително усъвършенстван чрез подравняване с човешки предпочитания, отхвърляне на проби и RL. Отличава се в сложно разсъждение, генериране на артефакти и структурирани изходи, достигайки нивото на GPT-4o и DeepSeek-V3-0324 в множество бенчмаркове.",
|
||||
"thudm/glm-4-32b:free.description": "GLM-4-32B-0414 е двуезичен (китайски/английски) модел с отворени тегла и 32B параметъра, оптимизиран за генериране на код, извикване на функции и агентни задачи. Предобучен върху 15T висококачествени и логически наситени данни и допълнително усъвършенстван чрез подравняване с човешки предпочитания, отхвърляне на проби и RL. Отличава се в сложно разсъждение, генериране на артефакти и структурирани изходи, достигайки нивото на GPT-4o и DeepSeek-V3-0324 в множество бенчмаркове.",
|
||||
"thudm/glm-4-9b-chat.description": "Отворената версия на най-новия предобучен модел GLM-4 от Zhipu AI.",
|
||||
"thudm/glm-z1-32b.description": "GLM-Z1-32B-0414 е подобрен вариант на GLM-4-32B, създаден за дълбоко математическо, логическо и кодово разсъждение. Използва разширено RL (специфично за задачи и общо предпочитание по двойки), за да подобри сложни многоетапни задачи. В сравнение с GLM-4-32B, Z1 значително подобрява структурираното разсъждение и способностите в формални домейни.\n\nПоддържа принудително „мислене“ чрез инженеринг на подканите, подобрена кохерентност за дълги изходи и е оптимизиран за агентни работни потоци с дълъг контекст (чрез YaRN), извикване на JSON инструменти и фино семплиране за стабилно разсъждение. Идеален за случаи, изискващи внимателни многоетапни или формални изводи.",
|
||||
"thudm/glm-z1-rumination-32b.description": "GLM Z1 Rumination 32B е 32B модел за дълбока аргументация от серията GLM-4-Z1, оптимизиран за сложни отворени задачи, изискващи продължително мислене. Изграден върху glm-4-32b-0414, добавя допълнителни етапи с подсилено обучение и многоетапно подравняване, въвеждайки способност за „размисъл“, симулираща разширена когнитивна обработка. Това включва итеративна аргументация, многостъпкова логика и работни потоци с инструменти като търсене, извличане и синтез с позовавания. Отличава се в изследователско писане, сравнителен анализ и сложни въпроси и отговори. Поддържа извикване на функции за търсене/навигация (`search`, `click`, `open`, `finish`) за агентни процеси. Поведението на размисъл се управлява чрез многократни цикли с правила за възнаграждение и отложени решения, тествани спрямо рамки за дълбоки изследвания като вътрешната система за подравняване на OpenAI. Този вариант е фокусиран върху дълбочина, а не скорост.",
|
||||
"tngtech/deepseek-r1t-chimera:free.description": "DeepSeek-R1T-Chimera е създаден чрез обединяване на DeepSeek-R1 и DeepSeek-V3 (0324), комбинирайки логиката на R1 с ефективността на токените от V3. Базиран е на DeepSeek-MoE Transformer и е оптимизиран за общо генериране на текст. Обединява предварително обучени тегла за баланс между логика, ефективност и следване на инструкции. Пуснат под MIT лиценз за изследователска и търговска употреба.",
|
||||
"togethercomputer/StripedHyena-Nous-7B.description": "StripedHyena Nous (7B) предлага подобрена изчислителна ефективност чрез своята архитектура и стратегия.",
|
||||
"tts-1-hd.description": "Най-новият модел за преобразуване на текст в реч, оптимизиран за качество.",
|
||||
"tts-1.description": "Най-новият модел за преобразуване на текст в реч, оптимизиран за реално време.",
|
||||
|
||||
@@ -58,24 +58,7 @@
|
||||
"agent.welcome.sentence.1": "Радвам се да се запознаем! Нека се опознаем по-добре.",
|
||||
"agent.welcome.sentence.2": "Какъв тип партньор искаш да бъда?",
|
||||
"agent.welcome.sentence.3": "Първо, дай ми име :)",
|
||||
"agent.welcome.suggestion.items.1.name": "Lumi",
|
||||
"agent.welcome.suggestion.items.1.prompt": "Нека първо ви нарека Lumi. Топло, внимателно и леко мечтателно.",
|
||||
"agent.welcome.suggestion.items.2.name": "Atlas",
|
||||
"agent.welcome.suggestion.items.2.prompt": "Какво ще кажете за Atlas? Уравновесен, надежден и добър в изпълнението на задачи.",
|
||||
"agent.welcome.suggestion.items.3.name": "Momo",
|
||||
"agent.welcome.suggestion.items.3.prompt": "Може би Momo. Непринудено, приветливо и лесно за разговор.",
|
||||
"agent.welcome.suggestion.items.4.name": "Nova",
|
||||
"agent.welcome.suggestion.items.4.prompt": "Нека бъде Nova. Проницателно, креативно и пълно със свежи идеи.",
|
||||
"agent.welcome.suggestion.items.5.name": "Milo",
|
||||
"agent.welcome.suggestion.items.5.prompt": "Milo звучи добре. Приятелско, бързо мислещо и тихо уверено.",
|
||||
"agent.welcome.suggestion.items.6.name": "Aster",
|
||||
"agent.welcome.suggestion.items.6.prompt": "Какво ще кажете за Aster? Чисто, директно и спокойно под напрежение.",
|
||||
"agent.welcome.suggestion.items.7.name": "Pixel",
|
||||
"agent.welcome.suggestion.items.7.prompt": "Да ви нарека Pixel? Любопитно, ориентирано към продуктите и чувствително към детайлите.",
|
||||
"agent.welcome.suggestion.items.8.name": "Echo",
|
||||
"agent.welcome.suggestion.items.8.prompt": "Може би Echo. Търпеливо, внимателно и винаги вслушващо се.",
|
||||
"agent.welcome.suggestion.items.9.name": "Orbit",
|
||||
"agent.welcome.suggestion.items.9.prompt": "Нека пробваме Orbit. Звучи като дългосрочен спътник, който расте заедно с мен.",
|
||||
"agent.welcome.suggestion.avatarHint": "Използвайте {{emoji}} като аватар.",
|
||||
"agent.welcome.suggestion.switch": "Покажи друг набор",
|
||||
"agent.welcome.suggestion.title": "Нуждаете се от отправна точка? Изберете име и по-късно можем да го прецизираме.",
|
||||
"agent.wrapUp.action": "Мисля, че сме готови",
|
||||
|
||||
@@ -35,6 +35,12 @@
|
||||
"builtins.lobe-agent-documents.apiName.renameDocument": "Преименуване на документ",
|
||||
"builtins.lobe-agent-documents.apiName.replaceDocumentContent": "Замени съдържанието на документа",
|
||||
"builtins.lobe-agent-documents.apiName.updateLoadRule": "Актуализиране на правило за зареждане",
|
||||
"builtins.lobe-agent-documents.inspector.chars": "{{count}} символа",
|
||||
"builtins.lobe-agent-documents.inspector.docCount": "{{count}} документа",
|
||||
"builtins.lobe-agent-documents.inspector.opsCount": "{{count}} операции",
|
||||
"builtins.lobe-agent-documents.inspector.opsResult": "{{success}}/{{total}} операции",
|
||||
"builtins.lobe-agent-documents.inspector.target.agent": "в агент",
|
||||
"builtins.lobe-agent-documents.inspector.target.currentTopic": "в тема",
|
||||
"builtins.lobe-agent-documents.title": "Документи на агент",
|
||||
"builtins.lobe-agent-management.apiName.callAgent": "Обаждане на агент",
|
||||
"builtins.lobe-agent-management.apiName.createAgent": "Създаване на агент",
|
||||
@@ -63,24 +69,34 @@
|
||||
"builtins.lobe-agent-management.render.installPlugin.plugin": "Плъгин",
|
||||
"builtins.lobe-agent-management.render.installPlugin.success": "Успешно инсталиран",
|
||||
"builtins.lobe-agent-management.title": "Мениджър на агенти",
|
||||
"builtins.lobe-agent-marketplace.apiName.showAgentMarketplace": "Отворете пазара за агенти",
|
||||
"builtins.lobe-agent-marketplace.apiName.submitAgentPick": "Изпратете избора на агент",
|
||||
"builtins.lobe-agent-marketplace.title": "Пазар за агенти",
|
||||
"builtins.lobe-claude-code.agent.instruction": "Инструкция",
|
||||
"builtins.lobe-claude-code.agent.result": "Резултат",
|
||||
"builtins.lobe-claude-code.todoWrite.allDone": "Всички задачи са изпълнени",
|
||||
"builtins.lobe-claude-code.todoWrite.currentStep": "Текуща стъпка",
|
||||
"builtins.lobe-claude-code.todoWrite.todos": "Задачи",
|
||||
"builtins.lobe-cloud-sandbox.apiName.editFile": "Редактиране на файл",
|
||||
"builtins.lobe-cloud-sandbox.apiName.editLocalFile": "Редактиране на файл",
|
||||
"builtins.lobe-cloud-sandbox.apiName.executeCode": "Изпълнение на код",
|
||||
"builtins.lobe-cloud-sandbox.apiName.exportFile": "Експортиране на файл",
|
||||
"builtins.lobe-cloud-sandbox.apiName.getCommandOutput": "Извличане на изход от команда",
|
||||
"builtins.lobe-cloud-sandbox.apiName.globFiles": "Търсене на файлове с глоб",
|
||||
"builtins.lobe-cloud-sandbox.apiName.globLocalFiles": "Търсене на файлове по шаблон",
|
||||
"builtins.lobe-cloud-sandbox.apiName.grepContent": "Търсене в съдържанието",
|
||||
"builtins.lobe-cloud-sandbox.apiName.killCommand": "Прекратяване на команда",
|
||||
"builtins.lobe-cloud-sandbox.apiName.listFiles": "Списък с файлове",
|
||||
"builtins.lobe-cloud-sandbox.apiName.listLocalFiles": "Списък с файлове",
|
||||
"builtins.lobe-cloud-sandbox.apiName.moveFiles": "Преместване на файлове",
|
||||
"builtins.lobe-cloud-sandbox.apiName.moveLocalFiles": "Преместване на файлове",
|
||||
"builtins.lobe-cloud-sandbox.apiName.readFile": "Четене на съдържание на файл",
|
||||
"builtins.lobe-cloud-sandbox.apiName.readLocalFile": "Прочитане на съдържание на файл",
|
||||
"builtins.lobe-cloud-sandbox.apiName.renameLocalFile": "Преименуване",
|
||||
"builtins.lobe-cloud-sandbox.apiName.runCommand": "Изпълнение на команда",
|
||||
"builtins.lobe-cloud-sandbox.apiName.searchFiles": "Търсене на файлове",
|
||||
"builtins.lobe-cloud-sandbox.apiName.searchLocalFiles": "Търсене на файлове",
|
||||
"builtins.lobe-cloud-sandbox.apiName.writeFile": "Запис на файл",
|
||||
"builtins.lobe-cloud-sandbox.apiName.writeLocalFile": "Запис на файл",
|
||||
"builtins.lobe-cloud-sandbox.inspector.noResults": "Няма резултати",
|
||||
"builtins.lobe-cloud-sandbox.title": "Облачна пясъчник среда",
|
||||
@@ -146,17 +162,24 @@
|
||||
"builtins.lobe-knowledge-base.inspector.andMoreFiles": "и още {{count}}",
|
||||
"builtins.lobe-knowledge-base.inspector.noResults": "Няма резултати",
|
||||
"builtins.lobe-knowledge-base.title": "Библиотека",
|
||||
"builtins.lobe-local-system.apiName.editFile": "Редактиране на файл",
|
||||
"builtins.lobe-local-system.apiName.editLocalFile": "Редактиране на файл",
|
||||
"builtins.lobe-local-system.apiName.getCommandOutput": "Извличане на изход от команда",
|
||||
"builtins.lobe-local-system.apiName.globFiles": "Търсене на файлове с глоб",
|
||||
"builtins.lobe-local-system.apiName.globLocalFiles": "Търсене на файлове по шаблон",
|
||||
"builtins.lobe-local-system.apiName.grepContent": "Търсене в съдържанието",
|
||||
"builtins.lobe-local-system.apiName.killCommand": "Прекратяване на команда",
|
||||
"builtins.lobe-local-system.apiName.listFiles": "Списък с файлове",
|
||||
"builtins.lobe-local-system.apiName.listLocalFiles": "Списък с файлове",
|
||||
"builtins.lobe-local-system.apiName.moveFiles": "Преместване на файлове",
|
||||
"builtins.lobe-local-system.apiName.moveLocalFiles": "Преместване на файлове",
|
||||
"builtins.lobe-local-system.apiName.readFile": "Четене на съдържание на файл",
|
||||
"builtins.lobe-local-system.apiName.readLocalFile": "Прочитане на съдържание на файл",
|
||||
"builtins.lobe-local-system.apiName.renameLocalFile": "Преименуване",
|
||||
"builtins.lobe-local-system.apiName.runCommand": "Изпълнение на команда",
|
||||
"builtins.lobe-local-system.apiName.searchFiles": "Търсене на файлове",
|
||||
"builtins.lobe-local-system.apiName.searchLocalFiles": "Търсене на файлове",
|
||||
"builtins.lobe-local-system.apiName.writeFile": "Запис на файл",
|
||||
"builtins.lobe-local-system.apiName.writeLocalFile": "Запис на файл",
|
||||
"builtins.lobe-local-system.inspector.noResults": "Няма резултати",
|
||||
"builtins.lobe-local-system.inspector.rename.result": "<old>{{oldName}}</old> → <new>{{newName}}</new>",
|
||||
@@ -233,6 +256,32 @@
|
||||
"builtins.lobe-skills.apiName.runCommand": "Изпълни команда",
|
||||
"builtins.lobe-skills.apiName.searchSkill": "Търсене на умения",
|
||||
"builtins.lobe-skills.title": "Умения",
|
||||
"builtins.lobe-task.apiName.createTask": "Създаване на задача",
|
||||
"builtins.lobe-task.apiName.createTasks": "Създаване на задачи",
|
||||
"builtins.lobe-task.apiName.deleteTask": "Изтриване на задача",
|
||||
"builtins.lobe-task.apiName.editTask": "Редактиране на задача",
|
||||
"builtins.lobe-task.apiName.listTasks": "Списък със задачи",
|
||||
"builtins.lobe-task.apiName.runTask": "Изпълнение на задача",
|
||||
"builtins.lobe-task.apiName.runTasks": "Изпълнение на задачи",
|
||||
"builtins.lobe-task.apiName.updateTaskStatus": "Актуализиране на статус",
|
||||
"builtins.lobe-task.apiName.viewTask": "Преглед на задача",
|
||||
"builtins.lobe-task.create.subtaskOf": "Подзадача на {{parent}}",
|
||||
"builtins.lobe-task.createTasks.count": "{{count}} задачи",
|
||||
"builtins.lobe-task.createTasks.failedCount": "{{count}} неуспешни",
|
||||
"builtins.lobe-task.createTasks.more": "+{{count}} още",
|
||||
"builtins.lobe-task.edit.assign": "назначаване",
|
||||
"builtins.lobe-task.edit.blocksOn": "блокира на",
|
||||
"builtins.lobe-task.edit.description": "описанието е актуализирано",
|
||||
"builtins.lobe-task.edit.instruction": "инструкцията е актуализирана",
|
||||
"builtins.lobe-task.edit.priority": "приоритет",
|
||||
"builtins.lobe-task.edit.rename": "преименуване",
|
||||
"builtins.lobe-task.edit.unassign": "премахване на назначение",
|
||||
"builtins.lobe-task.edit.unblocks": "отблокира",
|
||||
"builtins.lobe-task.run.continueTopic": "продължи темата",
|
||||
"builtins.lobe-task.runTasks.count": "{{count}} задачи",
|
||||
"builtins.lobe-task.runTasks.failedCount": "{{count}} неуспешни",
|
||||
"builtins.lobe-task.runTasks.more": "+{{count}} още",
|
||||
"builtins.lobe-task.title": "Инструменти за задачи",
|
||||
"builtins.lobe-topic-reference.apiName.getTopicContext": "Вземи контекста на темата",
|
||||
"builtins.lobe-topic-reference.title": "Препратка към тема",
|
||||
"builtins.lobe-user-interaction.apiName.askUserQuestion": "Задайте въпрос на потребителя",
|
||||
@@ -260,11 +309,18 @@
|
||||
"builtins.lobe-web-browsing.inspector.noResults": "Няма резултати",
|
||||
"builtins.lobe-web-browsing.title": "Уеб търсене",
|
||||
"builtins.lobe-web-onboarding.apiName.finishOnboarding": "Завършване на въвеждането",
|
||||
"builtins.lobe-web-onboarding.apiName.getOnboardingState": "Прочетете състоянието на въвеждането",
|
||||
"builtins.lobe-web-onboarding.apiName.readDocument": "Прочетете документа",
|
||||
"builtins.lobe-web-onboarding.apiName.saveUserQuestion": "Запазете въпроса на потребителя",
|
||||
"builtins.lobe-web-onboarding.apiName.updateDocument": "Актуализирайте документа",
|
||||
"builtins.lobe-web-onboarding.apiName.writeDocument": "Създаване на документ",
|
||||
"builtins.lobe-web-onboarding.docType.persona": "Потребителски профил",
|
||||
"builtins.lobe-web-onboarding.docType.soul": "SOUL.md",
|
||||
"builtins.lobe-web-onboarding.inspector.charCount_one": "{{count}} знак",
|
||||
"builtins.lobe-web-onboarding.inspector.charCount_other": "{{count}} знака",
|
||||
"builtins.lobe-web-onboarding.inspector.hunkCount_one": "{{count}} промяна",
|
||||
"builtins.lobe-web-onboarding.inspector.hunkCount_other": "{{count}} промени",
|
||||
"builtins.lobe-web-onboarding.inspector.interests_one": "{{count}} интерес",
|
||||
"builtins.lobe-web-onboarding.inspector.interests_other": "{{count}} интереса",
|
||||
"builtins.lobe-web-onboarding.title": "Въвеждане на потребител",
|
||||
"confirm": "Потвърди",
|
||||
"debug.arguments": "Аргументи",
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"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 модели и измерва използването с Кредити, свързани с токени на модела.",
|
||||
"longcat.description": "LongCat е серия от големи модели за генеративен AI, независимо разработени от Meituan. Той е създаден да подобри вътрешната продуктивност на предприятието и да позволи иновативни приложения чрез ефективна изчислителна архитектура и силни мултимодални възможности.",
|
||||
"minimax.description": "Основана през 2021 г., MiniMax създава универсален AI с мултимодални базови модели, включително текстови модели с трилиони параметри, речеви и визуални модели, както и приложения като Hailuo AI.",
|
||||
"minimaxcodingplan.description": "MiniMax Token Plan предоставя достъп до модели MiniMax, включително M2.7, за задачи, свързани с програмиране, чрез абонамент с фиксирана такса.",
|
||||
|
||||
@@ -454,16 +454,14 @@
|
||||
"myAgents.status.published": "Публикуван",
|
||||
"myAgents.status.unpublished": "Скрит",
|
||||
"myAgents.title": "Моите публикувани агенти",
|
||||
"notification.category.generation.desc": "Известия за довършване на изображения и видеа",
|
||||
"notification.category.generation.title": "Генериране",
|
||||
"notification.category.schedule.desc": "Неуспешни и прекъснати планирани изпълнения на агент",
|
||||
"notification.category.schedule.title": "Планирани задачи",
|
||||
"notification.email.desc": "Получавайте известия по имейл, когато се случват важни събития",
|
||||
"notification.email.title": "Известия по имейл",
|
||||
"notification.enabled": "Активирано",
|
||||
"notification.inbox.desc": "Показване на известия в приложението",
|
||||
"notification.inbox.title": "Известия в пощенската кутия",
|
||||
"notification.item.agent_cron_job_failed": "Неуспешни планирани задачи",
|
||||
"notification.item.agent_cron_job_failed": "Планираната задача не успя",
|
||||
"notification.item.image_generation_completed": "Генерирането на изображение завърши",
|
||||
"notification.item.video_generation_completed": "Генерирането на видео завърши",
|
||||
"notification.title": "Канали за известия",
|
||||
@@ -498,10 +496,13 @@
|
||||
"settingAppearance.animationMode.disabled": "Изключено",
|
||||
"settingAppearance.animationMode.elegant": "Елегантен",
|
||||
"settingAppearance.animationMode.title": "Анимация при отговор",
|
||||
"settingAppearance.appTray.desc": "Показване на иконата на LobeHub в системната лента или менюто на macOS. Деактивирането й също премахва достъпа до менюто на лентата.",
|
||||
"settingAppearance.appTray.title": "Показване на системната лента",
|
||||
"settingAppearance.contextMenuMode.default": "По подразбиране",
|
||||
"settingAppearance.contextMenuMode.desc": "Активиране на контекстно меню с десен бутон за някои елементи от списъка.",
|
||||
"settingAppearance.contextMenuMode.disabled": "Изключено",
|
||||
"settingAppearance.contextMenuMode.title": "Режим на контекстно меню",
|
||||
"settingAppearance.desktop.title": "Работен плот",
|
||||
"settingAppearance.neutralColor.desc": "Персонализирана сива гама с различни цветови нюанси",
|
||||
"settingAppearance.neutralColor.title": "Неутрален цвят",
|
||||
"settingAppearance.noAnimation.desc": "Изключване на всички анимационни ефекти в приложението",
|
||||
@@ -534,6 +535,9 @@
|
||||
"settingChat.inputTemplate.desc": "Последното съобщение на потребителя ще бъде вмъкнато в този шаблон",
|
||||
"settingChat.inputTemplate.placeholder": "Шаблон за предварителна обработка {{text}} ще бъде заменен с реално въведена информация",
|
||||
"settingChat.inputTemplate.title": "Предварителна обработка на входа",
|
||||
"settingChat.selfIteration.enabled.desc": "Allow this assistant to review recent signals and improve its own skills when the lab workflow runs",
|
||||
"settingChat.selfIteration.enabled.title": "Enable Self-Iteration",
|
||||
"settingChat.selfIteration.title": "Advanced Labs",
|
||||
"settingChat.submit": "Актуализирай предпочитанията за чат",
|
||||
"settingChat.title": "Настройки на чата",
|
||||
"settingChatAppearance.autoScrollOnStreaming.desc": "Автоматично превъртане до дъното, когато ИИ генерира отговор",
|
||||
@@ -889,6 +893,8 @@
|
||||
"tools.builtins.lobe-agent-documents.title": "Документи",
|
||||
"tools.builtins.lobe-agent-management.description": "Създаване, управление и оркестриране на AI агенти",
|
||||
"tools.builtins.lobe-agent-management.title": "Управление на агенти",
|
||||
"tools.builtins.lobe-agent-marketplace.description": "Показване на потребителите на подбрана карта на Пазара на агенти и записване на избраните от тях шаблони.",
|
||||
"tools.builtins.lobe-agent-marketplace.title": "Пазар на агенти",
|
||||
"tools.builtins.lobe-artifacts.description": "Генерирайте и визуализирайте интерактивни UI компоненти, визуализации на данни, диаграми, SVG графики и уеб приложения в реално време. Създавайте богато визуално съдържание, с което потребителите могат директно да взаимодействат.",
|
||||
"tools.builtins.lobe-artifacts.readme": "Генерирайте и визуализирайте интерактивни UI компоненти, визуализации на данни, диаграми, SVG графики и уеб приложения в реално време. Създавайте богато визуално съдържание, с което потребителите могат директно да взаимодействат.",
|
||||
"tools.builtins.lobe-artifacts.title": "Артефакти",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"table.columns.spend": "Кредити",
|
||||
"table.columns.startTime": "Създадено на",
|
||||
"table.columns.totalTokens": "Използвани токени",
|
||||
"table.columns.trigger.enums.agent_signal": "Сигнал от агент",
|
||||
"table.columns.trigger.enums.api": "API Обаждане",
|
||||
"table.columns.trigger.enums.bot": "Съобщение от бот",
|
||||
"table.columns.trigger.enums.chat": "Съобщение в чат",
|
||||
@@ -23,6 +24,7 @@
|
||||
"table.columns.trigger.enums.semantic_search": "Търсене на знания",
|
||||
"table.columns.trigger.enums.topic": "Резюме на тема",
|
||||
"table.columns.trigger.enums.video": "Генериране на видеа",
|
||||
"table.columns.trigger.enums.visual_analysis": "Визуален анализ",
|
||||
"table.columns.trigger.title": "Тригер",
|
||||
"table.columns.type.enums.chat": "Генериране на текст",
|
||||
"table.columns.type.enums.embedding": "Вграждане",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"action.connect.popupBlocked": "Изскачащият прозорец за свързване е блокиран. Разрешете изскачащите прозорци в браузъра си, за да продължите.",
|
||||
"action.create.error": "Неуспешно създаване на задача. Моля, опитайте отново.",
|
||||
"action.create.success": "Добавена е планирана задача. Намерете я в Lobe AI.",
|
||||
"action.createButton": "Добавете като планирана задача",
|
||||
"action.createButton": "Добави задача",
|
||||
"action.creating": "Създаване...",
|
||||
"action.dismiss.error": "Неуспешно отхвърляне. Моля, опитайте отново.",
|
||||
"action.dismiss.tooltip": "Не се интересувам",
|
||||
@@ -33,6 +33,7 @@
|
||||
"calendar-conflict-check.description": "Всяка сутрин, преглеждайте днешния ден за конфликти, последователни срещи, недостатъчно време за пътуване.",
|
||||
"calendar-conflict-check.prompt": "Всяка сутрин в 07:30 преглеждайте днешния календар за конфликти, последователни срещи или недостатъчно време за пътуване/буфер. Предложете корекции.",
|
||||
"calendar-conflict-check.title": "Проверка за конфликти в календара",
|
||||
"card.templateTag": "Шаблон",
|
||||
"cashflow-weekly.description": "Всеки понеделник, какво влиза тази седмица, какво излиза, големи разходи следващата седмица.",
|
||||
"cashflow-weekly.prompt": "Всеки понеделник в 09:00 преглеждайте паричния поток: вземания, дължими тази седмица, плащания, дължими, и големи разходи, планирани за следващата седмица.",
|
||||
"cashflow-weekly.title": "Седмичен паричен поток",
|
||||
@@ -211,6 +212,7 @@
|
||||
"repo-health-weekly.prompt": "Всеки понеделник в 09:00 преглеждайте хранилищата в GitHub, които поддържам: изоставане на проблеми, застой на PR, неуспехи на CI, предупреждения за зависимости. Изведете какво се нуждае от внимание тази седмица.",
|
||||
"repo-health-weekly.title": "Седмично здраве на хранилищата",
|
||||
"schedule.daily": "Всеки ден в {{time}}",
|
||||
"schedule.editableAfterCreateTooltip": "Можете да коригирате графика след създаването на задачата.",
|
||||
"schedule.weekly": "Всеки {{weekday}} в {{time}}",
|
||||
"section.title": "Опитайте тези планирани задачи",
|
||||
"seo-weekly-report.description": "Всеки понеделник, движение в класирането, нововъзникващи ключови думи и страници, които си струва да се обновят.",
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
"localFiles.grepContent.glob": "Филтър за файлове",
|
||||
"localFiles.grepContent.pattern": "Шаблон за търсене",
|
||||
"localFiles.grepContent.type": "Тип файл",
|
||||
"localFiles.listFiles.emptyDirectory": "Тази директория е празна",
|
||||
"localFiles.moveFiles.itemsMoved": "{{count}} елемент(а) преместени:",
|
||||
"localFiles.moveFiles.itemsMoved_one": "{{count}} елемент преместен:",
|
||||
"localFiles.moveFiles.itemsMoved_other": "{{count}} елемента преместени:",
|
||||
@@ -129,7 +130,6 @@
|
||||
"localFiles.writeFile.characters": "знаци",
|
||||
"localFiles.writeFile.preview": "Преглед на съдържанието",
|
||||
"localFiles.writeFile.truncated": "съкратено",
|
||||
"search.createNewSearch": "Създай нов запис за търсене",
|
||||
"search.emptyResult": "Няма намерени резултати, моля променете ключовите думи и опитайте отново",
|
||||
"search.genAiMessage": "Създай съобщение от агент",
|
||||
"search.includedTooltip": "Текущите резултати от търсенето ще бъдат включени в контекста на разговора",
|
||||
@@ -160,7 +160,6 @@
|
||||
"search.searchTimeRange.value.week": "В рамките на седмица",
|
||||
"search.searchTimeRange.value.year": "В рамките на година",
|
||||
"search.summary": "Обобщение",
|
||||
"search.summaryTooltip": "Обобщи текущото съдържание",
|
||||
"search.viewMoreResults": "Виж още {{results}} резултата",
|
||||
"securityBlacklist.awsCredentials": "Достъпът до AWS идентификационни данни може да изтече ключове за достъп до облака",
|
||||
"securityBlacklist.browserCredentials": "Достъпът до съхранени в браузъра идентификационни данни може да разкрие пароли",
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
"channel.userIdHint": "Ihre Benutzer-ID auf dieser Plattform. Die KI kann sie verwenden, um Ihnen Direktnachrichten zu senden.",
|
||||
"channel.userIdHint.discord": "Entwicklermodus aktivieren (Einstellungen → Erweitert), dann Rechtsklick auf Ihr Profilbild → Benutzer-ID kopieren.",
|
||||
"channel.userIdHint.feishu": "Öffnen Sie Ihre App auf der Feishu / Lark Open Platform → Berechtigungen und suchen Sie dort Ihre Open ID.",
|
||||
"channel.userIdHint.line": "Öffnen Sie die LINE Developers Console → Ihr Kanal → Registerkarte Grundeinstellungen, und kopieren Sie \"Ihre Benutzer-ID\" (beginnt mit U, 33 Zeichen).",
|
||||
"channel.userIdHint.qq": "Ihre QQ-Nummer, auf Ihrer QQ-Profilseite angezeigt.",
|
||||
"channel.userIdHint.slack": "Öffnen Sie Ihr Slack-Profil → ⋮ Mehr → Mitglieds-ID kopieren (beginnt mit U).",
|
||||
"channel.userIdHint.telegram": "Senden Sie irgendeine Nachricht an @userinfobot in Telegram — er antwortet mit Ihrer numerischen Benutzer-ID.",
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
"authModal.signIn": "Erneut anmelden",
|
||||
"authModal.signingIn": "Anmeldung läuft...",
|
||||
"authModal.title": "Sitzung abgelaufen",
|
||||
"betterAuth.captcha.continue": "Weiter",
|
||||
"betterAuth.captcha.description": "Führen Sie die Sicherheitsüberprüfung unten durch. Wir werden Ihre Anmeldung oder Registrierung automatisch fortsetzen.",
|
||||
"betterAuth.captcha.pendingDescription": "Bitte führen Sie zuerst die Überprüfung durch und fahren Sie dann fort.",
|
||||
"betterAuth.captcha.title": "Sicherheitsüberprüfung erforderlich",
|
||||
"betterAuth.errors.confirmPasswordRequired": "Bitte bestätigen Sie Ihr Passwort",
|
||||
"betterAuth.errors.emailExists": "Diese E-Mail ist bereits registriert. Bitte melden Sie sich stattdessen an",
|
||||
"betterAuth.errors.emailInvalid": "Bitte geben Sie eine gültige E-Mail-Adresse oder einen Benutzernamen ein",
|
||||
|
||||
+46
-2
@@ -24,6 +24,11 @@
|
||||
"agentProfile.knowledgeBases_other": "{{count}} Wissensbasen",
|
||||
"agentProfile.skills_one": "{{count}} Fähigkeit",
|
||||
"agentProfile.skills_other": "{{count}} Fähigkeiten",
|
||||
"agentSignal.receipts.memory.detail": "Für zukünftige Antworten gespeichert",
|
||||
"agentSignal.receipts.memory.title": "Erinnerung gespeichert",
|
||||
"agentSignal.receipts.recentActivity": "Letzte Aktivität",
|
||||
"agentSignal.receipts.skill.detail": "Verbessert, wie dieser Assistent ähnliche Anfragen bearbeitet",
|
||||
"agentSignal.receipts.skill.title": "Fähigkeit aktualisiert",
|
||||
"agents": "Agenten",
|
||||
"artifact.generating": "Wird generiert",
|
||||
"artifact.inThread": "In Unterthemen nicht einsehbar, bitte wechseln Sie zum Hauptgesprächsbereich",
|
||||
@@ -317,7 +322,6 @@
|
||||
"pageSelection.reference": "Ausgewählter Text",
|
||||
"pin": "Anheften",
|
||||
"pinOff": "Lösen",
|
||||
"prompts.summaryExpert": "Als Zusammenfassungsexperte fasse bitte den folgenden Inhalt basierend auf den obigen Systemanweisungen zusammen:",
|
||||
"rag.referenceChunks": "Referenzquelle",
|
||||
"rag.userQuery.actions.delete": "Abfrage-Neuschreibung löschen",
|
||||
"rag.userQuery.actions.regenerate": "Abfrage neu generieren",
|
||||
@@ -490,6 +494,7 @@
|
||||
"taskDetail.comment.edit": "Bearbeiten",
|
||||
"taskDetail.comment.save": "Speichern",
|
||||
"taskDetail.commentPlaceholder": "Kommentar hinterlassen...",
|
||||
"taskDetail.commentSubmitAndRun": "Senden & jetzt ausführen",
|
||||
"taskDetail.deleteConfirm.content": "Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"taskDetail.deleteConfirm.ok": "Löschen",
|
||||
"taskDetail.deleteConfirm.title": "Diese Aufgabe löschen?",
|
||||
@@ -514,6 +519,23 @@
|
||||
"taskDetail.properties": "Eigenschaften",
|
||||
"taskDetail.reassignDisabled": "Agent kann während der laufenden Aufgabe nicht neu zugewiesen werden",
|
||||
"taskDetail.rerunTask": "Aufgabe erneut ausführen",
|
||||
"taskDetail.runAll": "Alle ausführen",
|
||||
"taskDetail.runAll.cancel": "Abbrechen",
|
||||
"taskDetail.runAll.confirm": "{{count}} Unteraufgabe(n) ausführen",
|
||||
"taskDetail.runAll.cycleWarning": "Zirkuläre Abhängigkeit erkannt. Aufgaben, die in den Zyklus involviert oder davon blockiert sind, werden nicht ausgeführt: {{members}}",
|
||||
"taskDetail.runAll.description": "Unteraufgaben werden schichtweise ausgeführt. Jede Schicht wartet, bis die vorherige abgeschlossen ist. Aufgaben ohne Abhängigkeiten werden in Schicht 1 ausgeführt.",
|
||||
"taskDetail.runAll.empty": "Nichts auszuführen — jede Unteraufgabe ist bereits abgeschlossen, in Bearbeitung oder in einem Zyklus blockiert.",
|
||||
"taskDetail.runAll.kickedOff": "{{count}} Unteraufgabe(n) gestartet; nachfolgende Schichten folgen.",
|
||||
"taskDetail.runAll.layer": "Schicht {{index}}",
|
||||
"taskDetail.runAll.layerHint.first": "Startet sofort",
|
||||
"taskDetail.runAll.layerHint.next": "Wartet, bis Schicht {{prev}} abgeschlossen ist",
|
||||
"taskDetail.runAll.loading": "Unteraufgabenplan wird geladen...",
|
||||
"taskDetail.runAll.partialFailure": "{{ok}} von {{total}} Unteraufgabe(n) gestartet; {{failed}} fehlgeschlagen.",
|
||||
"taskDetail.runAll.skipped.alreadyDone": "{{count}} Aufgabe(n) bereits abgeschlossen oder abgebrochen — übersprungen",
|
||||
"taskDetail.runAll.skipped.blockedExternally": "{{count}} Aufgabe(n) warten auf einen externen Blocker — werden automatisch ausgeführt, wenn der Blocker entfernt wird",
|
||||
"taskDetail.runAll.skipped.ineligible": "{{count}} Aufgabe(n) laufen oder sind geplant — übersprungen",
|
||||
"taskDetail.runAll.title": "Unteraufgaben in Abhängigkeitsreihenfolge ausführen",
|
||||
"taskDetail.runNow": "Jetzt ausführen",
|
||||
"taskDetail.runTask": "Aufgabe ausführen",
|
||||
"taskDetail.saveModelConfig": "Speichern",
|
||||
"taskDetail.status.backlog": "Backlog",
|
||||
@@ -599,6 +621,7 @@
|
||||
"taskSchedule.scheduleType.weekly": "Wöchentlich",
|
||||
"taskSchedule.scheduler": "Planer",
|
||||
"taskSchedule.schedulerTab": "Planer",
|
||||
"taskSchedule.startScheduling": "Planung starten",
|
||||
"taskSchedule.summary.daily": "Täglich um {{time}}",
|
||||
"taskSchedule.summary.disabled": "Automatisierung ist deaktiviert",
|
||||
"taskSchedule.summary.everyNHours": "Alle {{count}} Stunden{{minute}}",
|
||||
@@ -762,7 +785,6 @@
|
||||
"workflow.toolDisplayName.finishOnboarding": "Onboarding abgeschlossen",
|
||||
"workflow.toolDisplayName.getCommandOutput": "Befehlsausgabe lesen",
|
||||
"workflow.toolDisplayName.getDocument": "Dokument lesen",
|
||||
"workflow.toolDisplayName.getOnboardingState": "Onboarding-Status überprüft",
|
||||
"workflow.toolDisplayName.getPageContent": "Seiteninhalt lesen",
|
||||
"workflow.toolDisplayName.getTopicContext": "Themenkontext lesen",
|
||||
"workflow.toolDisplayName.globLocalFiles": "Durchsuchte Dateien",
|
||||
@@ -786,6 +808,7 @@
|
||||
"workflow.toolDisplayName.replaceDocumentContent": "Dokumenteninhalt ersetzt",
|
||||
"workflow.toolDisplayName.replaceText": "Ersetzter Text",
|
||||
"workflow.toolDisplayName.runCommand": "Befehl ausgeführt",
|
||||
"workflow.toolDisplayName.saveUserQuestion": "Informationen aufgezeichnet",
|
||||
"workflow.toolDisplayName.search": "Im Web gesucht",
|
||||
"workflow.toolDisplayName.searchAgent": "Gesuchte Agenten",
|
||||
"workflow.toolDisplayName.searchKnowledgeBase": "Wissensdatenbank durchsucht",
|
||||
@@ -799,6 +822,7 @@
|
||||
"workflow.toolDisplayName.updateLoadRule": "Aktualisierte Lastregel",
|
||||
"workflow.toolDisplayName.updatePlan": "Aktualisierter Plan",
|
||||
"workflow.toolDisplayName.updateTodos": "Todos aktualisiert",
|
||||
"workflow.toolDisplayName.writeDocument": "Ein Dokument geschrieben",
|
||||
"workflow.toolDisplayName.writeLocalFile": "Datei wurde geschrieben",
|
||||
"workflow.working": "Wird ausgeführt...",
|
||||
"workingPanel.agentDocuments": "Agent Documents",
|
||||
@@ -830,8 +854,28 @@
|
||||
"workingPanel.resources.renameEmpty": "Title cannot be empty",
|
||||
"workingPanel.resources.renameError": "Failed to rename document",
|
||||
"workingPanel.resources.renameSuccess": "Document renamed",
|
||||
"workingPanel.resources.updatedAt": "Aktualisiert {{time}}",
|
||||
"workingPanel.resources.viewMode.list": "Listenansicht",
|
||||
"workingPanel.resources.viewMode.tree": "Baumansicht",
|
||||
"workingPanel.review.binary": "Binärdatei — Diff wird nicht angezeigt",
|
||||
"workingPanel.review.collapseAll": "Alle einklappen",
|
||||
"workingPanel.review.copied": "Pfad kopiert",
|
||||
"workingPanel.review.copyPath": "Dateipfad kopieren",
|
||||
"workingPanel.review.empty": "Keine Änderungen im Arbeitsbaum",
|
||||
"workingPanel.review.error": "Konnte den Diff dieser Datei nicht laden",
|
||||
"workingPanel.review.expandAll": "Alle ausklappen",
|
||||
"workingPanel.review.more": "Weitere Optionen",
|
||||
"workingPanel.review.refresh": "Aktualisieren",
|
||||
"workingPanel.review.textDiff.disable": "Inline-Textvergleich deaktivieren",
|
||||
"workingPanel.review.textDiff.enable": "Inline-Textvergleich aktivieren",
|
||||
"workingPanel.review.title": "Überprüfung",
|
||||
"workingPanel.review.tooLarge": "Datei ist zu groß, um inline verglichen zu werden",
|
||||
"workingPanel.review.unstaged": "Nicht gestaged",
|
||||
"workingPanel.review.viewMode.split": "Zur geteilten Ansicht wechseln",
|
||||
"workingPanel.review.viewMode.unified": "Zur einheitlichen Ansicht wechseln",
|
||||
"workingPanel.review.wordWrap.disable": "Zeilenumbruch deaktivieren",
|
||||
"workingPanel.review.wordWrap.enable": "Zeilenumbruch aktivieren",
|
||||
"workingPanel.space": "Leerzeichen",
|
||||
"workingPanel.title": "Working Panel",
|
||||
"you": "Du",
|
||||
"zenMode": "Zen-Modus"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user