Compare commits

...

26 Commits

Author SHA1 Message Date
ONLY-yours 6f1380b07c feat(creds): add secure credential input mode via human intervention
Allow users to save credentials securely without exposing values in AI
context. When AI calls saveCreds with `fields` but no `values`, a secure
form renders via the intervention system for direct user input.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 17:04:40 +08:00
Arvin Xu 13e8ef9c7b 💄 style(brief): show artifacts in card and extract DocumentModal (#14339)
*  feat(brief): show artifacts in card and extract DocumentModal

Wire `brief.artifacts` (already populated by topic-brief synthesis) into
TaskBriefCard and the home BriefCard so completed-topic deliverables
show up inline; clicking a doc card opens it in a modal.

The per-task PageModal becomes a reusable `DocumentModal` (props-based:
documentId/open/onClose), and the preview trigger state moves from task
store to a new `preview` slice in document store — any surface can now
call `useDocumentStore.openDocumentPreview(id)`.

Also:
- PageAgentPanelOverrideProvider: ephemeral right-panel state for
  PageEditor in transient surfaces (modal); defaults collapsed and
  doesn't write the persisted global preference.
- PageEditor.fullWidthHeader: layout flag so the modal's header spans
  both columns instead of the left pane only.

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

* 💄 style(shared-tool-ui): unify label-to-content spacing in file inspectors

Replace trailing-space spacing with explicit 6px marginInlineEnd on the label
span in Read/Edit/Write/List inspectors so they match the 6px gap already used
by chip-based renderers (Bash, Grep, Glob).

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

* 🐛 fix(brief): clear preview state on document modal teardown

`previewDocumentId` is global (`useDocumentStore`) and the modal opens on
any truthy value. Without cleanup, navigating away with the modal open
left a stale id behind, and the next surface that mounted a preview
modal (e.g. /home daily brief) would immediately reopen the old doc.

Extract a `<DocumentPreviewModal />` connector that resets the preview
state on unmount, and use it everywhere the global preview should be
rendered (TaskDetailPage, DailyBrief). Future mount points get the
cleanup for free.

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

* 🐛 fix(brief): coerce globalExpand to boolean in panel control hook

`systemStatusSelectors.showPageAgentPanel` returns `boolean | undefined`
(zenMode short-circuit ANDs with an optional flag), but
`PageAgentPanelControl.expand` is `boolean`. Coerce with `!!` so the
non-override branch satisfies the type.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 14:34:19 +08:00
CanYuanA 8387067807 🐛 fix: fix PDF chunking logic to prevent vectorization failure (#14327) 2026-04-30 13:55:36 +08:00
Tsuki 375e6381ce feat(mobile-router): add task and brief routers (#14337)
 feat(mobile-router): add task and brief routers to mobile tRPC router

Expose task and brief endpoints to the mobile client so the React Native
app can manage tasks and daily briefs via the same tRPC contract used by
the web client.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 13:09:38 +08:00
Arvin Xu f7c1ebf652 🚀 release: sync main branch to canary (#14317)
Automatic sync from main to canary. Merge conflicts detected.

**Resolution steps:**
```bash
git fetch origin
git checkout sync/main-to-canary-20260429-25113686179
git merge origin/main
# Resolve conflicts
git add -A && git commit
git push
```

> Do NOT merge canary into a main-based branch — always merge main INTO
the canary-based branch to keep a clean commit graph.
2026-04-30 13:08:39 +08:00
Arvin Xu 156a870cf3 🐛 fix(model-runtime): preserve LLM finishReason through callbacks transformer (#14336)
* 🐛 fix(model-runtime): preserve LLM finishReason through callbacks transformer

Soft interrupts from providers (Gemini RECITATION / MAX_TOKENS, etc.)
emit a `type: 'stop'` chunk carrying the finishReason string, but
`createCallbacksTransformer` was only using it as a terminal-event flag
and never aggregating the value. Downstream the `OnFinishData` payload
had no `finishReason` field, so RuntimeExecutors recorded an `llm_result`
event without it — the harness silently rendered an empty assistant
message even though tokens were billed.

Capture the value in the callbacks aggregator, surface it on
`OnFinishData`, and write it into the `llm_result` tracing event so
soft-interrupt cases are diagnosable.

Fixes LOBE-8403

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

* 🐛 fix(model-runtime): keep first finishReason across multi-stop streams

Anthropic emits two `'stop'` chunks per stream — `message_delta` with
the real `stop_reason` (`end_turn` / `max_tokens` / `tool_use`) followed
by a `message_stop` sentinel. Last-write-wins clobbered the meaningful
reason with the sentinel string, defeating the very tracing signal this
fix is meant to provide.

Switch to first-non-empty-wins so the real provider reason survives.
The empty-string fallback covers cases where an early provider chunk
arrives before the reason is known.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 12:46:30 +08:00
Innei f017dcd0ea test: fix home cold route CI coverage 2026-04-30 12:40:31 +08:00
lobehubbot 719a554456 🔖 chore(release): release version v2.1.55 [skip ci] 2026-04-30 12:37:58 +08:00
Innei 3b1eef72d8 🐛 fix(chat): preserve topics across cold route sends (#14284)
**Hotfix Scope:** Topic preservation across cold chat-entry routes

> Keeps newly created Topics visible when a first message is sent before
the destination chat route has fully hydrated.

- **Page Agent empty-session regression** — Sending the first message in
an empty Page Agent panel no longer clears the newly created Topic and
returns the panel to an empty state. (Resolves LOBE-8351)
- **Home cold-route send regression** — Sending from the Home default
Chat Input now routes to the newly created Inbox Topic even when
`/agent/:aid` has never been opened and the route chunk has no warm
cache.
- **Page-scoped Copilot consistency** — Page Copilot and File Copilot
share the same provider-level topic reset behavior, so stale Topics are
cleared only when entering or switching the scoped Agent.
- **Regression coverage** — Added focused unit coverage for Home default
sends, route parity coverage remains intact, and added an E2E scenario
for the no-cache Home send path.

- `bunx vitest run --silent='passed-only'
'src/routes/(main)/home/features/InputArea/useSend.test.ts'
'src/spa/router/desktopRouter.sync.test.tsx'
'src/routes/(main)/agent/features/Conversation/ChatHydration/index.test.tsx'
'src/routes/(main)/agent/_layout/AgentIdSync.test.tsx'`
- `BASE_URL=http://localhost:3007
DATABASE_URL=postgresql://postgres:postgres@localhost:5433/postgres bun
run test -- --tags '@HOME-CHAT-COLD-001'` from `e2e/`

- Self-hosted: pull the new image and restart. No schema or environment
changes.
- Cloud: ships through the normal hotfix deployment after merge.

@Innei

Fixes LOBE-8351
2026-04-30 12:37:58 +08:00
lobehubbot 9e20cd6b3a 🔖 chore(release): release version v2.1.54 [skip ci] 2026-04-30 12:37:18 +08:00
LobeHub Bot a5f4b4b569 🌐 chore: translate non-English comments to English in agent-runtime examples and siliconcloud provider (#14332)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 12:14:03 +08:00
LiJian 5a15f759d6 refactor(creds): add local/desktop credential injection guidance (#14306)
*  feat(creds): add local/desktop credential injection guidance

Teach AI how to use credentials in non-sandbox (desktop/local) environments via
getPlaintextCred + runCommand inline env vars, alongside the existing sandbox flow.

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

* 🔒 fix(creds): use runCommand env param for secure credential passing

Inline secrets in the command string would be visible in the Intervention UI
and logs. Use runCommand's env parameter instead, and correct the misleading
file credential guidance (getPlaintextCred returns a fileUrl, not a local path).

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 12:07:29 +08:00
Arvin Xu b7ecf2fd4d feat(agent,working-sidebar): add Review tab with bulk git diffs (#14334)
 feat(agent,working-sidebar): add Review tab with bulk git working-tree diffs

Adds a Codex-style Review tab to the agent working sidebar (peer to the
existing Resources content, surfaced as Space). When the active topic has a
working directory bound, the sidebar shows two chip-style tabs — Space (left)
and Review (right) — and the Review pane lists every dirty file with its
unified diff rendered via PatchDiff.

A single new IPC method `git.getGitWorkingTreePatches(dirPath)` enumerates
the working tree once via `git status --porcelain -z`, then runs every
per-file `git diff` in parallel inside main; tracked entries hit
`git diff HEAD -- <file>` while pure untracked files use
`git diff --no-index /dev/null <file>`. Each patch is capped at 256 KB and
classified into added / modified / deleted with additions/deletions counts
parsed off the patch text, so the renderer needs exactly one round trip and
zero per-file fetches.

The Review pane defaults to all files expanded, with PatchDiff render gated
on the panel's expanded state so collapsed entries don't pay the shiki
highlight cost. Adds a unified/split viewMode toggle in the Review subheader,
shows an Unstaged-N chip alongside it, and ships a custom small expand caret.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 11:53:49 +08:00
Tsuki 24062bb412 💄 style(daily-brief): add skeleton loading state (#14333)
💄 style(daily-brief): add skeleton loading state for DailyBrief component

LOBE-8400

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 11:40:14 +08:00
LobeHub Bot 61d432a991 🤖 style: update i18n (#14330)
💄 style: update i18n

Co-authored-by: canisminor1990 <17870709+canisminor1990@users.noreply.github.com>
2026-04-30 10:17:41 +08:00
Arvin Xu f59954137a 💄 style(task): add start-scheduling button in automation popover (#14323)
*  feat(task): add start-scheduling button in automation popover

Lets users mark a configured task as "scheduled" without firing an
immediate run, so the cron/heartbeat tick owns the first execution.

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

* 🐛 fix(task): hide start-scheduling button in heartbeat mode

Heartbeat tasks are re-armed only by maybeRearmHeartbeat after a topic
completes — there is no dispatcher that picks up `scheduled` heartbeat
tasks, so the button would leave a paused/backlog task dormant.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 10:03:52 +08:00
Neko 1324b67590 ♻️ refactor(server): agent signal now is easier to use (#14326) 2026-04-30 05:36:26 +08:00
Neko f390d04ef2 🐛 fix(server): prefer to use tool call id first (#14322) 2026-04-30 05:07:51 +08:00
Arvin Xu 84df8a9994 ♻️ refactor(task-brief): auto-synthesize topic briefs (#14324)
*  feat(task-lifecycle): auto-synthesize topic briefs (LOBE-8333)

Replaces agent-driven createBrief on the non-review "done" path with a
programmatic synthesis: rule-based decision + DB-collected artifacts +
a dedicated LLM for user-facing title/summary. Handoff and brief stay
separate (agent-internal vs user-facing language) and the new path is
gated behind task.config.brief.mode === 'auto' so existing tasks keep
the legacy tool-driven behavior until the GrowthBook flag flips.

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

*  feat(generate-brief): let LLM gate emission per topic content

Pure rules can only skip the obvious cases (error, judge-handled,
automation tick, trivial content). They can't tell that "I clarified
my understanding and will start drafting next" is a working note, not
a delivery. Add an `emit: boolean` to GENERATE_BRIEF_SCHEMA and have
the prompt instruct the model to judge — emit=false discards the
brief without writing to the table.

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

* ♻️ refactor(task-model): move topic-artifact query into TaskModel

DB queries belong on the model, not in a service helper. Replaces
the standalone collectTopicArtifacts() with TaskModel.getDocumentsPinnedSince(),
which lives next to pinDocument / getPinnedDocuments and returns
joined { id, kind, title } rows. synthesize.ts is now pure decision
logic — no more drizzle imports.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 00:58:39 +08:00
YuTengjing 9aea74659f 🐛 fix: restore task agent panel toggle (#14321) 2026-04-30 00:46:28 +08:00
Arvin Xu 105321bfe1 🐛 fix(file-loaders): support UTF-16 encoded text files in TextLoader (#13615)
* 🐛 fix: support UTF-16 encoded text files in TextLoader

The TextLoader previously hardcoded UTF-8 encoding when reading files,
causing UTF-16 encoded CSVs (e.g. Google Ads Keyword Planner exports)
to be parsed with null bytes, producing garbled content and database
insert failures.

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

* ♻️ refactor(file-loaders): tighten TextLoader UTF-16 detection

- Use TextDecoder('utf-16be') instead of manual byte-swap loop, which
  also avoided in-place mutation of the read buffer.
- Replace the 2-byte heuristic with a 512-byte sample, count ASCII-pair
  shape on both halves so UTF-16BE without BOM is detected too, and
  files whose first character is non-ASCII no longer slip through.
- Add tests for UTF-8 BOM, UTF-16LE no-BOM, and UTF-16BE no-BOM.

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 23:59:50 +08:00
YuTengjing b0b6e67d5f feat: support DeepSeek Anthropic runtime (#14312) 2026-04-29 23:57:18 +08:00
YuTengjing d2aa3cd1b4 🐛 fix(model-bank): reject lobehub model ids no longer in the bank (#14261) 2026-04-29 23:52:11 +08:00
AmAzing- babdc6ade5 Fix task drawer agent metadata hydration (#14315) 2026-04-29 22:55:55 +08:00
YuTengjing 7e6255096a ♻️ refactor: use virtual model id for default onboarding model (#14311) 2026-04-29 22:44:20 +08:00
Neko 0e7eda4b47 feat(agent-signal,server,prompts,builtin-tool-memory): score based orchestration, consolidate better (#14314) 2026-04-29 22:42:58 +08:00
266 changed files with 13247 additions and 855 deletions
+50
View File
@@ -2,6 +2,56 @@
# Changelog
### [Version 2.1.55](https://github.com/lobehub/lobe-chat/compare/v2.1.54...v2.1.55)
<sup>Released on **2026-04-29**</sup>
#### 🐛 Bug Fixes
- **chat**: preserve topics across cold route sends.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **chat**: preserve topics across cold route sends, closes [#14284](https://github.com/lobehub/lobe-chat/issues/14284) ([b8fe675](https://github.com/lobehub/lobe-chat/commit/b8fe675))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 2.1.54](https://github.com/lobehub/lobe-chat/compare/v2.1.53...v2.1.54)
<sup>Released on **2026-04-27**</sup>
#### 🐛 Bug Fixes
- **misc**: clear stale topic when switching agents from a topic route.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **misc**: clear stale topic when switching agents from a topic route, closes [#14231](https://github.com/lobehub/lobe-chat/issues/14231) ([deeb97a](https://github.com/lobehub/lobe-chat/commit/deeb97a))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 2.1.52](https://github.com/lobehub/lobe-chat/compare/v2.1.51...v2.1.52)
<sup>Released on **2026-04-20**</sup>
+165
View File
@@ -8,10 +8,13 @@ import type {
GitBranchInfo,
GitBranchListItem,
GitCheckoutResult,
GitFileDiffStatus,
GitLinkedPullRequestResult,
GitPullResult,
GitPushResult,
GitWorkingTreeFiles,
GitWorkingTreePatch,
GitWorkingTreePatches,
GitWorkingTreeStatus,
} from '@lobechat/electron-client-ipc';
@@ -261,6 +264,168 @@ 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.
*
* 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).
*
* 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.
*/
@IpcMethod()
async getGitWorkingTreePatches(dirPath: string): Promise<GitWorkingTreePatches> {
const MAX_PATCH_BYTES = 256 * 1024;
const execFileAsync = promisify(execFile);
interface Entry {
filePath: string;
isUntracked: boolean;
status: GitFileDiffStatus;
}
// 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.
const entries: Entry[] = [];
try {
const { stdout } = await execFileAsync('git', ['status', '--porcelain', '-z'], {
cwd: dirPath,
timeout: 5000,
});
const tokens = stdout.split('\0');
let i = 0;
while (i < tokens.length) {
const entry = tokens[i];
i++;
if (entry.length < 3) continue;
const x = entry[0];
const y = entry[1];
const filePath = entry.slice(3);
// R/C entries carry an extra source-path token we must consume.
if (x === 'R' || x === 'C') i++;
if (!filePath) continue;
if (x === '?' && y === '?') {
entries.push({ filePath, isUntracked: true, status: 'added' });
} else if (x === '!' && y === '!') {
// ignored
} else if (x === 'D' || y === 'D') {
entries.push({ filePath, isUntracked: false, status: 'deleted' });
} else if (x === 'A' || y === 'A') {
entries.push({ filePath, isUntracked: false, status: 'added' });
} else {
entries.push({ filePath, isUntracked: false, status: 'modified' });
}
}
} catch (error: any) {
logger.warn('[getGitWorkingTreePatches] status failed', {
cwd: dirPath,
stderr: error?.stderr?.toString?.() ?? error?.stderr,
});
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++;
}
return { additions, deletions };
};
// 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,
};
}),
);
// Re-bucket so the UI sees added → modified → deleted (matches the
// working-tree popover order).
const order: Record<GitFileDiffStatus, number> = { added: 0, modified: 1, deleted: 2 };
patches.sort((a, b) => order[a.status] - order[b.status]);
return { patches };
}
/**
* Count commits HEAD is ahead/behind its upstream tracking ref.
* Returns `hasUpstream: false` when the branch has no upstream configured
+12
View File
@@ -1,4 +1,16 @@
[
{
"children": {},
"date": "2026-04-29",
"version": "2.1.55"
},
{
"children": {
"fixes": ["clear stale topic when switching agents from a topic route."]
},
"date": "2026-04-27",
"version": "2.1.54"
},
{
"children": {},
"date": "2026-04-20",
+14
View File
@@ -0,0 +1,14 @@
@journey @home @chat-input
Feature: Home 页面默认 Chat Input 发送链路
Home Topic
Background:
Given
@HOME-CHAT-COLD-001 @P0
Scenario: 首次打开 Agent 路由且无缓存时,Home 默认输入发送后应跳转到新建 Topic
Given Home Agent
When "cold route home message"
And Enter Home
Then Topic
And "cold route home message"
+137
View File
@@ -0,0 +1,137 @@
import { After, Given, Then, When } from '@cucumber/cucumber';
import { expect } from '@playwright/test';
import { llmMockManager } from '../../mocks/llm';
import type { CustomWorld } from '../../support/world';
import { WAIT_TIMEOUT } from '../../support/world';
const COLD_ROUTE_SCRIPT_DELAY = 2500;
const delay = (ms: number) =>
new Promise((resolve) => {
setTimeout(resolve, ms);
});
const focusHomeChatInput = async (world: CustomWorld): Promise<void> => {
const candidates = [
world.page.locator('[data-testid="chat-input"] textarea'),
world.page.locator('[data-testid="chat-input"] [contenteditable="true"]'),
world.page.getByRole('textbox'),
world.page.locator('[data-testid="chat-input"]'),
];
for (const locator of candidates) {
const count = await locator.count();
for (let index = 0; index < count; index += 1) {
const item = locator.nth(index);
const visible = await item.isVisible().catch(() => false);
if (!visible) continue;
await item.click({ force: true });
return;
}
}
throw new Error('Could not find a visible Home chat input to focus');
};
Given(
'用户在冷启动 Home 页面并延迟 Agent 路由加载',
{ timeout: 45_000 },
async function (this: CustomWorld) {
console.log(' 📍 Step: 设置快速 LLM mock...');
llmMockManager.clearResponses();
llmMockManager.setConfig({
responseDelay: 0,
streamChunkSize: 1024,
streamDelay: 0,
});
llmMockManager.setResponse('cold route home message', 'cold route response');
await llmMockManager.setup(this.page);
console.log(' 📍 Step: 注册冷路由脚本延迟...');
this.testContext.delayColdAgentScripts = false;
await this.page.route('**/*', async (route) => {
const request = route.request();
const url = request.url();
const shouldDelay =
this.testContext.delayColdAgentScripts === true &&
request.resourceType() === 'script' &&
(url.includes('/_next/static/') ||
url.includes('/src/routes/(main)/agent') ||
url.includes('/src/routes/%28main%29/agent'));
if (shouldDelay) {
console.log(` ⏳ Delaying cold agent script: ${url}`);
await delay(COLD_ROUTE_SCRIPT_DELAY);
}
await route.continue();
});
console.log(' 📍 Step: 导航到 Home 页面...');
await this.page.goto('/');
const chatInputContainer = this.page.locator('[data-testid="chat-input"]').first();
await expect(chatInputContainer).toBeVisible({ timeout: WAIT_TIMEOUT });
console.log(' ✅ 已进入冷启动 Home 页面');
},
);
When(
'用户在输入框中输入 {string}',
{ timeout: 30_000 },
async function (this: CustomWorld, text: string) {
console.log(` 📍 Step: 在 Home 输入框中输入 "${text}"...`);
await focusHomeChatInput(this);
await this.page.keyboard.type(text, { delay: 20 });
console.log(' ✅ 已输入 Home 默认消息');
},
);
When('用户按 Enter 从 Home 默认输入发送', { timeout: 45_000 }, async function (this: CustomWorld) {
console.log(' 📍 Step: 启用冷路由延迟并发送默认 Home 消息...');
await this.page.waitForTimeout(200);
this.testContext.delayColdAgentScripts = true;
await this.page.keyboard.press('Enter');
await this.page.waitForURL(/\/agent\/[^/?#]+/, { timeout: WAIT_TIMEOUT });
console.log(' ✅ 已触发 Home 默认发送');
});
Then('页面应该跳转到新建 Topic 对话页面', { timeout: 45_000 }, async function (this: CustomWorld) {
console.log(' 📍 Step: 验证 URL 进入新建 Topic...');
await this.page.waitForURL(/\/agent\/[^/?#]+\/[^/?#]+/, { timeout: 30_000 });
const currentUrl = this.page.url();
expect(currentUrl).toMatch(/\/agent\/[^/?#]+\/[^/?#]+/);
console.log(` ✅ 已跳转到 Topic 页面: ${currentUrl}`);
});
Then(
'用户消息 {string} 应该保留在对话中',
{ timeout: 45_000 },
async function (this: CustomWorld, message: string) {
console.log(` 📍 Step: 验证用户消息仍在对话中: ${message}`);
await expect(this.page.getByText(message).first()).toBeVisible({ timeout: WAIT_TIMEOUT });
console.log(' ✅ 用户消息已保留在对话中');
},
);
After({ tags: '@chat-input' }, async function (this: CustomWorld) {
llmMockManager.resetConfig();
llmMockManager.clearResponses();
this.testContext.delayColdAgentScripts = false;
});
+35
View File
@@ -1,3 +1,5 @@
import { randomBytes } from 'node:crypto';
import bcrypt from 'bcryptjs';
// Test user credentials - these are used for e2e testing only
@@ -92,6 +94,39 @@ export async function seedTestUser(): Promise<void> {
}
}
export async function createTestSession(): Promise<string | null> {
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) {
console.log('⚠️ DATABASE_URL not set, cannot create test session');
return null;
}
await seedTestUser();
const { default: pg } = await import('pg');
const client = new pg.Client({ connectionString: databaseUrl });
try {
await client.connect();
const now = new Date();
const expiresAt = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
const sessionId = randomBytes(9).toString('base64url');
const sessionToken = randomBytes(24).toString('base64url');
await client.query(
`INSERT INTO auth_sessions (id, token, user_id, expires_at, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $5)`,
[sessionId, sessionToken, TEST_USER.id, expiresAt.toISOString(), now.toISOString()],
);
return sessionToken;
} finally {
await client.end();
}
}
/**
* Clean up test user data after tests
*/
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "وكيل الإعداد الحالي",
"tool.intervention.onboarding.agentIdentity.targets": "ينطبق على",
"tool.intervention.onboarding.agentIdentity.title": "تأكيد تحديث هوية الوكيل",
"tool.intervention.onboarding.userProfile.applyHint": "سيتم حفظ هذه التفاصيل في ملفك الشخصي بعد الموافقة.",
"tool.intervention.onboarding.userProfile.description": "الموافقة على هذا التغيير ستحدث ملف تعريف الانضمام الخاص بك حتى يتمكن الوكيل من تخصيص الردود المستقبلية.",
"tool.intervention.onboarding.userProfile.eyebrow": "الموافقة على الانضمام",
"tool.intervention.onboarding.userProfile.fullName": "الاسم الكامل",
"tool.intervention.onboarding.userProfile.responseLanguage": "لغة الرد",
"tool.intervention.onboarding.userProfile.title": "تأكيد تحديث ملفك الشخصي",
"tool.intervention.pending": "قيد الانتظار",
"tool.intervention.reject": "رفض",
"tool.intervention.rejectAndContinue": "رفض وإعادة المحاولة",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "إعدادات Ollama غير صالحة، يرجى التحقق منها والمحاولة مجددًا.",
"response.InvalidProviderAPIKey": "مفتاح API الخاص بـ {{provider}} غير صحيح أو فارغ، يرجى التحقق منه والمحاولة مجددًا.",
"response.InvalidVertexCredentials": "فشل التوثيق مع Vertex. يرجى التحقق من بيانات الاعتماد والمحاولة مجددًا.",
"response.LobeHubModelDeprecated": "النموذج \"{{model}}\" لم يعد متاحًا. يرجى اختيار نموذج حالي من محدد النماذج.",
"response.LocationNotSupportError": "نعتذر، لا يدعم موقعك الحالي هذه الخدمة. قد يكون ذلك بسبب قيود إقليمية أو عدم توفر الخدمة. يرجى التأكد من دعم الموقع الحالي أو المحاولة من موقع مختلف.",
"response.ModelNotFound": "عذرًا، لم يتم العثور على النموذج المطلوب. قد لا يكون موجودًا أو ليس لديك صلاحية الوصول. يرجى المحاولة بعد تغيير مفتاح API أو تعديل الصلاحيات.",
"response.NoOpenAIAPIKey": "مفتاح OpenAI API فارغ، يرجى إضافة مفتاح API مخصص.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "اتصل بـ {{provider}}",
"action.connect.error": "فشل الاتصال، يرجى المحاولة مرة أخرى.",
"action.connect.popupBlocked": "تم حظر نافذة الاتصال المنبثقة. اسمح بالنوافذ المنبثقة في متصفحك للمتابعة.",
"action.create.error": "فشل في إنشاء المهمة. يرجى المحاولة مرة أخرى.",
"action.create.success": "تمت إضافة المهمة المجدولة. يمكنك العثور عليها في Lobe AI.",
"action.createButton": "أضف كمهمة مجدولة",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "استخدام الرموز",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "تعليمات مفصلة للوكيل لتنفيذ هذه المهمة...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "عنوان المهمة...",
"agentMarketplace.category.businessStrategy": "الأعمال والاستراتيجية",
"agentMarketplace.category.contentCreation": "إنشاء المحتوى",
"agentMarketplace.category.creatorEconomy": "اقتصاد المبدعين",
"agentMarketplace.category.designCreative": "التصميم والإبداع",
"agentMarketplace.category.engineering": "الهندسة",
"agentMarketplace.category.financeLegal": "المالية والقانونية",
"agentMarketplace.category.learningResearch": "التعلم والبحث",
"agentMarketplace.category.marketing": "التسويق",
"agentMarketplace.category.operations": "العمليات",
"agentMarketplace.category.peopleHR": "الموارد البشرية",
"agentMarketplace.category.personalLife": "الحياة الشخصية",
"agentMarketplace.category.productManagement": "إدارة المنتجات",
"agentMarketplace.category.salesCustomer": "المبيعات وخدمة العملاء",
"agentMarketplace.picker.empty": "لا توجد قوالب متاحة.",
"agentMarketplace.picker.failedToLoad": "فشل في تحميل القوالب. يرجى المحاولة مرة أخرى لاحقًا.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} قوالب متاحة.",
"codeInterpreter-legacy.error": "خطأ في التنفيذ",
"codeInterpreter-legacy.executing": "جارٍ التنفيذ...",
"codeInterpreter-legacy.files": "الملفات:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Текущ агент за въвеждане",
"tool.intervention.onboarding.agentIdentity.targets": "Отнася се за",
"tool.intervention.onboarding.agentIdentity.title": "Потвърждение за обновяване на идентичността на агента",
"tool.intervention.onboarding.userProfile.applyHint": "Тези данни ще бъдат запазени във вашия профил след одобрение.",
"tool.intervention.onboarding.userProfile.description": "Одобряването на тази промяна актуализира вашия профил за въвеждане, така че агентът да може да персонализира бъдещите отговори.",
"tool.intervention.onboarding.userProfile.eyebrow": "Одобрение на въвеждане",
"tool.intervention.onboarding.userProfile.fullName": "Пълно име",
"tool.intervention.onboarding.userProfile.responseLanguage": "Език на отговора",
"tool.intervention.onboarding.userProfile.title": "Потвърдете актуализацията на профила си",
"tool.intervention.pending": "В очакване",
"tool.intervention.reject": "Отхвърли",
"tool.intervention.rejectAndContinue": "Отхвърли и опитай отново",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Невалидна конфигурация на Ollama. Проверете настройките и опитайте отново.",
"response.InvalidProviderAPIKey": "Невалиден или празен API ключ за {{provider}}. Проверете го и опитайте отново.",
"response.InvalidVertexCredentials": "Неуспешна автентикация с Vertex. Проверете данните си и опитайте отново.",
"response.LobeHubModelDeprecated": "Моделът \"{{model}}\" вече не е наличен. Моля, изберете актуален модел от селектора на модели.",
"response.LocationNotSupportError": "Съжаляваме, услугата не се поддържа във вашето местоположение. Проверете дали е налична или опитайте от друго място.",
"response.ModelNotFound": "Съжаляваме, моделът не бе намерен. Може да не съществува или нямате достъп. Опитайте с друг API ключ или коригирайте правата си.",
"response.NoOpenAIAPIKey": "OpenAI API ключът е празен. Добавете персонализиран OpenAI API ключ.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "Свържете се с {{provider}}",
"action.connect.error": "Свързването не бе успешно, моля опитайте отново.",
"action.connect.popupBlocked": "Изскачащият прозорец за свързване е блокиран. Разрешете изскачащите прозорци в браузъра си, за да продължите.",
"action.create.error": "Неуспешно създаване на задача. Моля, опитайте отново.",
"action.create.success": "Добавена е планирана задача. Намерете я в Lobe AI.",
"action.createButton": "Добавете като планирана задача",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Използвани токени",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Подробни инструкции за агента за изпълнение на задачата...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Заглавие на задачата...",
"agentMarketplace.category.businessStrategy": "Бизнес и стратегия",
"agentMarketplace.category.contentCreation": "Създаване на съдържание",
"agentMarketplace.category.creatorEconomy": "Икономика на създателите",
"agentMarketplace.category.designCreative": "Дизайн и креативност",
"agentMarketplace.category.engineering": "Инженерство",
"agentMarketplace.category.financeLegal": "Финанси и право",
"agentMarketplace.category.learningResearch": "Обучение и изследвания",
"agentMarketplace.category.marketing": "Маркетинг",
"agentMarketplace.category.operations": "Операции",
"agentMarketplace.category.peopleHR": "Хора и ЧР",
"agentMarketplace.category.personalLife": "Личен живот",
"agentMarketplace.category.productManagement": "Управление на продукти",
"agentMarketplace.category.salesCustomer": "Продажби и клиенти",
"agentMarketplace.picker.empty": "Няма налични шаблони.",
"agentMarketplace.picker.failedToLoad": "Неуспешно зареждане на шаблоните. Моля, опитайте отново по-късно.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} налични шаблони.",
"codeInterpreter-legacy.error": "Грешка при изпълнение",
"codeInterpreter-legacy.executing": "Изпълнение...",
"codeInterpreter-legacy.files": "Файлове:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Aktueller Onboarding-Agent",
"tool.intervention.onboarding.agentIdentity.targets": "Gilt für",
"tool.intervention.onboarding.agentIdentity.title": "Aktualisierung der Agentenidentität bestätigen",
"tool.intervention.onboarding.userProfile.applyHint": "Diese Angaben werden nach Genehmigung in Ihrem Profil gespeichert.",
"tool.intervention.onboarding.userProfile.description": "Die Genehmigung dieser Änderung aktualisiert Ihr Onboarding-Profil, damit der Agent zukünftige Antworten anpassen kann.",
"tool.intervention.onboarding.userProfile.eyebrow": "Onboarding-Genehmigung",
"tool.intervention.onboarding.userProfile.fullName": "Vollständiger Name",
"tool.intervention.onboarding.userProfile.responseLanguage": "Antwortsprache",
"tool.intervention.onboarding.userProfile.title": "Bestätigen Sie Ihre Profilaktualisierung",
"tool.intervention.pending": "Ausstehend",
"tool.intervention.reject": "Ablehnen",
"tool.intervention.rejectAndContinue": "Ablehnen und erneut versuchen",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Ungültige Ollama-Konfiguration. Bitte prüfen Sie die Einstellungen.",
"response.InvalidProviderAPIKey": "{{provider}} API-Schlüssel ist ungültig oder leer. Bitte prüfen Sie den Schlüssel.",
"response.InvalidVertexCredentials": "Vertex-Authentifizierung fehlgeschlagen. Bitte Zugangsdaten prüfen.",
"response.LobeHubModelDeprecated": "Das Modell \"{{model}}\" ist nicht mehr verfügbar. Bitte wählen Sie ein aktuelles Modell aus dem Modellwähler aus.",
"response.LocationNotSupportError": "Ihr aktueller Standort unterstützt diesen Dienst nicht. Bitte Standort prüfen.",
"response.ModelNotFound": "Das angeforderte Modell wurde nicht gefunden oder Sie haben keinen Zugriff.",
"response.NoOpenAIAPIKey": "OpenAI API-Schlüssel fehlt. Bitte fügen Sie einen benutzerdefinierten Schlüssel hinzu.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "Verbinden mit {{provider}}",
"action.connect.error": "Verbindung fehlgeschlagen, bitte versuchen Sie es erneut.",
"action.connect.popupBlocked": "Verbindungspopup blockiert. Erlauben Sie Popups in Ihrem Browser, um fortzufahren.",
"action.create.error": "Aufgabe konnte nicht erstellt werden. Bitte versuchen Sie es erneut.",
"action.create.success": "Geplante Aufgabe hinzugefügt. Finden Sie sie in Lobe AI.",
"action.createButton": "Als geplante Aufgabe hinzufügen",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Token-Verbrauch",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Detaillierte Anweisung für den Agenten zur Ausführung dieser Aufgabe...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Aufgabentitel...",
"agentMarketplace.category.businessStrategy": "Geschäft & Strategie",
"agentMarketplace.category.contentCreation": "Inhaltserstellung",
"agentMarketplace.category.creatorEconomy": "Schöpferökonomie",
"agentMarketplace.category.designCreative": "Design & Kreatives",
"agentMarketplace.category.engineering": "Ingenieurwesen",
"agentMarketplace.category.financeLegal": "Finanzen & Recht",
"agentMarketplace.category.learningResearch": "Lernen & Forschung",
"agentMarketplace.category.marketing": "Marketing",
"agentMarketplace.category.operations": "Betrieb",
"agentMarketplace.category.peopleHR": "Personal & HR",
"agentMarketplace.category.personalLife": "Privatleben",
"agentMarketplace.category.productManagement": "Produktmanagement",
"agentMarketplace.category.salesCustomer": "Vertrieb & Kunden",
"agentMarketplace.picker.empty": "Keine Vorlagen verfügbar.",
"agentMarketplace.picker.failedToLoad": "Vorlagen konnten nicht geladen werden. Bitte versuchen Sie es später erneut.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} Vorlagen verfügbar.",
"codeInterpreter-legacy.error": "Ausführungsfehler",
"codeInterpreter-legacy.executing": "Wird ausgeführt...",
"codeInterpreter-legacy.files": "Dateien:",
+16
View File
@@ -599,6 +599,7 @@
"taskSchedule.scheduleType.weekly": "Weekly",
"taskSchedule.scheduler": "Scheduler",
"taskSchedule.schedulerTab": "Scheduled",
"taskSchedule.startScheduling": "Start scheduling",
"taskSchedule.summary.daily": "Daily at {{time}}",
"taskSchedule.summary.disabled": "Automation is off",
"taskSchedule.summary.everyNHours": "Every {{count}} hours{{minute}}",
@@ -667,6 +668,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Current onboarding Agent",
"tool.intervention.onboarding.agentIdentity.targets": "Applies to",
"tool.intervention.onboarding.agentIdentity.title": "Confirm Agent identity update",
"tool.intervention.onboarding.userProfile.applyHint": "These details will be saved to your profile after approval.",
"tool.intervention.onboarding.userProfile.description": "Approving this change updates your onboarding profile so the Agent can tailor future replies.",
"tool.intervention.onboarding.userProfile.eyebrow": "Onboarding approval",
"tool.intervention.onboarding.userProfile.fullName": "Full name",
"tool.intervention.onboarding.userProfile.responseLanguage": "Response language",
"tool.intervention.onboarding.userProfile.title": "Confirm your profile update",
"tool.intervention.pending": "Pending",
"tool.intervention.reject": "Reject",
"tool.intervention.rejectAndContinue": "Reject and Retry",
@@ -826,6 +833,15 @@
"workingPanel.resources.renameSuccess": "Document renamed",
"workingPanel.resources.viewMode.list": "List view",
"workingPanel.resources.viewMode.tree": "Tree view",
"workingPanel.review.binary": "Binary file — diff not shown",
"workingPanel.review.empty": "No working tree changes",
"workingPanel.review.error": "Couldn't load this file's diff",
"workingPanel.review.title": "Review",
"workingPanel.review.tooLarge": "File is too large to diff inline",
"workingPanel.review.unstaged": "Unstaged",
"workingPanel.review.viewMode.split": "Switch to split view",
"workingPanel.review.viewMode.unified": "Switch to unified view",
"workingPanel.space": "Space",
"workingPanel.title": "Working Panel",
"you": "You",
"zenMode": "Zen Mode"
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Invalid Ollama configuration, please check Ollama configuration and try again",
"response.InvalidProviderAPIKey": "{{provider}} API Key is incorrect or empty, please check your {{provider}} API Key and try again",
"response.InvalidVertexCredentials": "Vertex authentication failed. Please check your credentials and try again.",
"response.LobeHubModelDeprecated": "The model \"{{model}}\" is no longer available. Please pick a current model from the model selector.",
"response.LocationNotSupportError": "We're sorry, your current location does not support this model service. This may be due to regional restrictions or the service not being available. Please confirm if the current location supports using this service, or try using a different location.",
"response.ModelNotFound": "Sorry, the requested model could not be found. It may not exist or you may not have the necessary access permissions. Please try again after changing the API Key or adjusting your access permissions.",
"response.NoOpenAIAPIKey": "OpenAI API Key is empty, please add a custom OpenAI API Key",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "Connect {{provider}}",
"action.connect.error": "Connection failed, please try again.",
"action.connect.popupBlocked": "Connection popup blocked. Allow popups in your browser to continue.",
"action.create.error": "Failed to create task. Please try again.",
"action.create.success": "Scheduled task added. Find it in Lobe AI.",
"action.createButton": "Add as scheduled task",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Token Usage",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Detailed instruction for the agent to perform this task...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Task title...",
"agentMarketplace.category.businessStrategy": "Business & Strategy",
"agentMarketplace.category.contentCreation": "Content Creation",
"agentMarketplace.category.creatorEconomy": "Creator Economy",
"agentMarketplace.category.designCreative": "Design & Creative",
"agentMarketplace.category.engineering": "Engineering",
"agentMarketplace.category.financeLegal": "Finance & Legal",
"agentMarketplace.category.learningResearch": "Learning & Research",
"agentMarketplace.category.marketing": "Marketing",
"agentMarketplace.category.operations": "Operations",
"agentMarketplace.category.peopleHR": "People & HR",
"agentMarketplace.category.personalLife": "Personal Life",
"agentMarketplace.category.productManagement": "Product Management",
"agentMarketplace.category.salesCustomer": "Sales & Customer",
"agentMarketplace.picker.empty": "No templates available.",
"agentMarketplace.picker.failedToLoad": "Failed to load templates. Please try again later.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} templates available.",
"codeInterpreter-legacy.error": "Execution Error",
"codeInterpreter-legacy.executing": "Executing...",
"codeInterpreter-legacy.files": "Files:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Agente de incorporación actual",
"tool.intervention.onboarding.agentIdentity.targets": "Se aplica a",
"tool.intervention.onboarding.agentIdentity.title": "Confirmar actualización de identidad del agente",
"tool.intervention.onboarding.userProfile.applyHint": "Estos detalles se guardarán en tu perfil después de la aprobación.",
"tool.intervention.onboarding.userProfile.description": "Aprobar este cambio actualiza tu perfil de incorporación para que el Agente pueda personalizar futuras respuestas.",
"tool.intervention.onboarding.userProfile.eyebrow": "Aprobación de incorporación",
"tool.intervention.onboarding.userProfile.fullName": "Nombre completo",
"tool.intervention.onboarding.userProfile.responseLanguage": "Idioma de respuesta",
"tool.intervention.onboarding.userProfile.title": "Confirma la actualización de tu perfil",
"tool.intervention.pending": "Pendiente",
"tool.intervention.reject": "Rechazar",
"tool.intervention.rejectAndContinue": "Rechazar e intentar de nuevo",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Configuración inválida de Ollama. Verifica los ajustes.",
"response.InvalidProviderAPIKey": "La API Key de {{provider}} es incorrecta o está vacía. Verifícala.",
"response.InvalidVertexCredentials": "Error de autenticación de Vertex. Verifica tus credenciales.",
"response.LobeHubModelDeprecated": "El modelo \"{{model}}\" ya no está disponible. Por favor, elija un modelo actual del selector de modelos.",
"response.LocationNotSupportError": "Lo sentimos, tu ubicación actual no admite este servicio. Intenta desde otra ubicación.",
"response.ModelNotFound": "Lo sentimos, no se encontró el modelo solicitado. Verifica el acceso o cambia la API Key.",
"response.NoOpenAIAPIKey": "La API Key de OpenAI está vacía. Agrega una personalizada.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "Conectar {{provider}}",
"action.connect.error": "Conexión fallida, por favor intenta de nuevo.",
"action.connect.popupBlocked": "Ventana emergente de conexión bloqueada. Permite ventanas emergentes en tu navegador para continuar.",
"action.create.error": "No se pudo crear la tarea. Por favor, inténtalo de nuevo.",
"action.create.success": "Tarea programada añadida. Encuéntrala en Lobe AI.",
"action.createButton": "Añadir como tarea programada",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Uso de Tokens",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Instrucciones detalladas para que el agente realice esta tarea...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Título de la tarea...",
"agentMarketplace.category.businessStrategy": "Negocios y Estrategia",
"agentMarketplace.category.contentCreation": "Creación de Contenido",
"agentMarketplace.category.creatorEconomy": "Economía del Creador",
"agentMarketplace.category.designCreative": "Diseño y Creatividad",
"agentMarketplace.category.engineering": "Ingeniería",
"agentMarketplace.category.financeLegal": "Finanzas y Legal",
"agentMarketplace.category.learningResearch": "Aprendizaje e Investigación",
"agentMarketplace.category.marketing": "Marketing",
"agentMarketplace.category.operations": "Operaciones",
"agentMarketplace.category.peopleHR": "Personas y RRHH",
"agentMarketplace.category.personalLife": "Vida Personal",
"agentMarketplace.category.productManagement": "Gestión de Producto",
"agentMarketplace.category.salesCustomer": "Ventas y Atención al Cliente",
"agentMarketplace.picker.empty": "No hay plantillas disponibles.",
"agentMarketplace.picker.failedToLoad": "No se pudieron cargar las plantillas. Por favor, inténtelo de nuevo más tarde.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} plantillas disponibles.",
"codeInterpreter-legacy.error": "Error de Ejecución",
"codeInterpreter-legacy.executing": "Ejecutando...",
"codeInterpreter-legacy.files": "Archivos:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "عامل راه‌اندازی فعلی",
"tool.intervention.onboarding.agentIdentity.targets": "اعمال می‌شود بر",
"tool.intervention.onboarding.agentIdentity.title": "تأیید به‌روزرسانی هویت عامل",
"tool.intervention.onboarding.userProfile.applyHint": "این جزئیات پس از تأیید به پروفایل شما ذخیره خواهد شد.",
"tool.intervention.onboarding.userProfile.description": "تأیید این تغییر، پروفایل ورود شما را به‌روزرسانی می‌کند تا نماینده بتواند پاسخ‌های آینده را متناسب کند.",
"tool.intervention.onboarding.userProfile.eyebrow": "تأیید ورود",
"tool.intervention.onboarding.userProfile.fullName": "نام کامل",
"tool.intervention.onboarding.userProfile.responseLanguage": "زبان پاسخ",
"tool.intervention.onboarding.userProfile.title": "به‌روزرسانی پروفایل خود را تأیید کنید",
"tool.intervention.pending": "در انتظار",
"tool.intervention.reject": "رد کردن",
"tool.intervention.rejectAndContinue": "رد و تلاش مجدد",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "پیکربندی Ollama نامعتبر است. لطفاً تنظیمات را بررسی کرده و دوباره تلاش کنید.",
"response.InvalidProviderAPIKey": "کلید API {{provider}} نادرست یا خالی است. لطفاً آن را بررسی کرده و دوباره تلاش کنید.",
"response.InvalidVertexCredentials": "احراز هویت Vertex ناموفق بود. لطفاً اطلاعات ورود را بررسی کرده و دوباره تلاش کنید.",
"response.LobeHubModelDeprecated": "مدل \"{{model}}\" دیگر در دسترس نیست. لطفاً یک مدل فعلی از انتخابگر مدل انتخاب کنید.",
"response.LocationNotSupportError": "متأسفیم، موقعیت مکانی فعلی شما از این سرویس پشتیبانی نمی‌کند. لطفاً بررسی کنید که آیا این موقعیت از سرویس پشتیبانی می‌کند یا از مکان دیگری استفاده کنید.",
"response.ModelNotFound": "متأسفیم، مدل درخواستی یافت نشد. ممکن است وجود نداشته باشد یا دسترسی لازم را نداشته باشید. لطفاً کلید API را تغییر داده یا مجوزها را بررسی کنید.",
"response.NoOpenAIAPIKey": "کلید API OpenAI خالی است. لطفاً یک کلید API سفارشی اضافه کنید.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "اتصال به {{provider}}",
"action.connect.error": "اتصال ناموفق بود، لطفاً دوباره تلاش کنید.",
"action.connect.popupBlocked": "پنجره پاپ‌آپ اتصال مسدود شده است. برای ادامه، پاپ‌آپ‌ها را در مرورگر خود مجاز کنید.",
"action.create.error": "ایجاد وظیفه ناموفق بود. لطفاً دوباره تلاش کنید.",
"action.create.success": "وظیفه زمان‌بندی شده اضافه شد. آن را در Lobe AI پیدا کنید.",
"action.createButton": "افزودن به عنوان وظیفه زمان‌بندی شده",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "مصرف توکن",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "دستورالعمل دقیق برای انجام این وظیفه توسط عامل...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "عنوان وظیفه...",
"agentMarketplace.category.businessStrategy": "کسب و کار و استراتژی",
"agentMarketplace.category.contentCreation": "ایجاد محتوا",
"agentMarketplace.category.creatorEconomy": "اقتصاد خالق",
"agentMarketplace.category.designCreative": "طراحی و خلاقیت",
"agentMarketplace.category.engineering": "مهندسی",
"agentMarketplace.category.financeLegal": "مالی و حقوقی",
"agentMarketplace.category.learningResearch": "آموزش و پژوهش",
"agentMarketplace.category.marketing": "بازاریابی",
"agentMarketplace.category.operations": "عملیات",
"agentMarketplace.category.peopleHR": "منابع انسانی",
"agentMarketplace.category.personalLife": "زندگی شخصی",
"agentMarketplace.category.productManagement": "مدیریت محصول",
"agentMarketplace.category.salesCustomer": "فروش و مشتری",
"agentMarketplace.picker.empty": "هیچ قالبی موجود نیست.",
"agentMarketplace.picker.failedToLoad": "بارگذاری قالب‌ها ناموفق بود. لطفاً بعداً دوباره تلاش کنید.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} قالب‌ها موجود است.",
"codeInterpreter-legacy.error": "خطای اجرا",
"codeInterpreter-legacy.executing": "در حال اجرا...",
"codeInterpreter-legacy.files": "فایل‌ها:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Agent donboarding actuel",
"tool.intervention.onboarding.agentIdentity.targets": "Sapplique à",
"tool.intervention.onboarding.agentIdentity.title": "Confirmer la mise à jour de lidentité de lagent",
"tool.intervention.onboarding.userProfile.applyHint": "Ces détails seront enregistrés dans votre profil après approbation.",
"tool.intervention.onboarding.userProfile.description": "L'approbation de ce changement met à jour votre profil d'intégration afin que l'Agent puisse adapter les réponses futures.",
"tool.intervention.onboarding.userProfile.eyebrow": "Approbation d'intégration",
"tool.intervention.onboarding.userProfile.fullName": "Nom complet",
"tool.intervention.onboarding.userProfile.responseLanguage": "Langue de réponse",
"tool.intervention.onboarding.userProfile.title": "Confirmez la mise à jour de votre profil",
"tool.intervention.pending": "En attente",
"tool.intervention.reject": "Rejeter",
"tool.intervention.rejectAndContinue": "Rejeter et réessayer",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Configuration Ollama invalide. Veuillez vérifier et réessayer.",
"response.InvalidProviderAPIKey": "La clé API {{provider}} est incorrecte ou vide. Veuillez la vérifier et réessayer.",
"response.InvalidVertexCredentials": "Échec de l'authentification Vertex. Veuillez vérifier vos identifiants et réessayer.",
"response.LobeHubModelDeprecated": "Le modèle \"{{model}}\" n'est plus disponible. Veuillez choisir un modèle actuel dans le sélecteur de modèles.",
"response.LocationNotSupportError": "Désolé, votre emplacement actuel ne prend pas en charge ce service. Veuillez vérifier les restrictions régionales ou essayer depuis un autre lieu.",
"response.ModelNotFound": "Désolé, le modèle demandé est introuvable. Il se peut qu'il n'existe pas ou que vous n'ayez pas les autorisations nécessaires.",
"response.NoOpenAIAPIKey": "Clé API OpenAI vide. Veuillez ajouter une clé API personnalisée.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "Connecter {{provider}}",
"action.connect.error": "Échec de la connexion, veuillez réessayer.",
"action.connect.popupBlocked": "Fenêtre contextuelle de connexion bloquée. Autorisez les fenêtres contextuelles dans votre navigateur pour continuer.",
"action.create.error": "Échec de la création de la tâche. Veuillez réessayer.",
"action.create.success": "Tâche planifiée ajoutée. Retrouvez-la dans Lobe AI.",
"action.createButton": "Ajouter comme tâche planifiée",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Utilisation des jetons",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Instructions détaillées pour que lagent exécute cette tâche...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Titre de la tâche...",
"agentMarketplace.category.businessStrategy": "Affaires et Stratégie",
"agentMarketplace.category.contentCreation": "Création de Contenu",
"agentMarketplace.category.creatorEconomy": "Économie des Créateurs",
"agentMarketplace.category.designCreative": "Design & Créatif",
"agentMarketplace.category.engineering": "Ingénierie",
"agentMarketplace.category.financeLegal": "Finance & Juridique",
"agentMarketplace.category.learningResearch": "Apprentissage & Recherche",
"agentMarketplace.category.marketing": "Marketing",
"agentMarketplace.category.operations": "Opérations",
"agentMarketplace.category.peopleHR": "Ressources Humaines",
"agentMarketplace.category.personalLife": "Vie Personnelle",
"agentMarketplace.category.productManagement": "Gestion de Produit",
"agentMarketplace.category.salesCustomer": "Ventes & Clientèle",
"agentMarketplace.picker.empty": "Aucun modèle disponible.",
"agentMarketplace.picker.failedToLoad": "Échec du chargement des modèles. Veuillez réessayer plus tard.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} modèles disponibles.",
"codeInterpreter-legacy.error": "Erreur d'exécution",
"codeInterpreter-legacy.executing": "Exécution en cours...",
"codeInterpreter-legacy.files": "Fichiers :",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Agente di onboarding attuale",
"tool.intervention.onboarding.agentIdentity.targets": "Si applica a",
"tool.intervention.onboarding.agentIdentity.title": "Conferma aggiornamento identità dellagente",
"tool.intervention.onboarding.userProfile.applyHint": "Questi dettagli verranno salvati nel tuo profilo dopo l'approvazione.",
"tool.intervention.onboarding.userProfile.description": "Approvando questa modifica, il tuo profilo di onboarding verrà aggiornato in modo che l'Agente possa personalizzare le risposte future.",
"tool.intervention.onboarding.userProfile.eyebrow": "Approvazione onboarding",
"tool.intervention.onboarding.userProfile.fullName": "Nome completo",
"tool.intervention.onboarding.userProfile.responseLanguage": "Lingua di risposta",
"tool.intervention.onboarding.userProfile.title": "Conferma l'aggiornamento del tuo profilo",
"tool.intervention.pending": "In sospeso",
"tool.intervention.reject": "Rifiuta",
"tool.intervention.rejectAndContinue": "Rifiuta e riprova",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Configurazione Ollama non valida. Controlla le impostazioni e riprova.",
"response.InvalidProviderAPIKey": "La chiave API di {{provider}} è errata o vuota. Verifica e riprova.",
"response.InvalidVertexCredentials": "Autenticazione Vertex fallita. Verifica le credenziali e riprova.",
"response.LobeHubModelDeprecated": "Il modello \"{{model}}\" non è più disponibile. Si prega di scegliere un modello attuale dal selettore di modelli.",
"response.LocationNotSupportError": "Spiacenti, il tuo paese non supporta questo servizio. Potrebbero esserci restrizioni regionali. Verifica la disponibilità o prova da un'altra posizione.",
"response.ModelNotFound": "Spiacenti, il modello richiesto non è stato trovato. Potrebbe non esistere o mancare l'autorizzazione. Prova a cambiare API Key o i permessi.",
"response.NoOpenAIAPIKey": "Chiave API OpenAI mancante. Aggiungi una chiave personalizzata.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "Connetti {{provider}}",
"action.connect.error": "Connessione fallita, per favore riprova.",
"action.connect.popupBlocked": "Popup di connessione bloccato. Consenti i popup nel tuo browser per continuare.",
"action.create.error": "Impossibile creare l'attività. Riprova.",
"action.create.success": "Attività programmata aggiunta. Trovala in Lobe AI.",
"action.createButton": "Aggiungi come attività programmata",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Utilizzo Token",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Istruzioni dettagliate per l'agente per eseguire questo compito...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Titolo del compito...",
"agentMarketplace.category.businessStrategy": "Business & Strategia",
"agentMarketplace.category.contentCreation": "Creazione di Contenuti",
"agentMarketplace.category.creatorEconomy": "Economia dei Creatori",
"agentMarketplace.category.designCreative": "Design & Creatività",
"agentMarketplace.category.engineering": "Ingegneria",
"agentMarketplace.category.financeLegal": "Finanza & Legale",
"agentMarketplace.category.learningResearch": "Apprendimento & Ricerca",
"agentMarketplace.category.marketing": "Marketing",
"agentMarketplace.category.operations": "Operazioni",
"agentMarketplace.category.peopleHR": "Persone & Risorse Umane",
"agentMarketplace.category.personalLife": "Vita Personale",
"agentMarketplace.category.productManagement": "Gestione del Prodotto",
"agentMarketplace.category.salesCustomer": "Vendite & Clienti",
"agentMarketplace.picker.empty": "Nessun modello disponibile.",
"agentMarketplace.picker.failedToLoad": "Caricamento dei modelli fallito. Per favore riprova più tardi.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} modelli disponibili.",
"codeInterpreter-legacy.error": "Errore di Esecuzione",
"codeInterpreter-legacy.executing": "Esecuzione in corso...",
"codeInterpreter-legacy.files": "File:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "現在のオンボーディングエージェント",
"tool.intervention.onboarding.agentIdentity.targets": "対象",
"tool.intervention.onboarding.agentIdentity.title": "エージェントのアイデンティティ更新を確認",
"tool.intervention.onboarding.userProfile.applyHint": "これらの詳細は承認後にあなたのプロフィールに保存されます。",
"tool.intervention.onboarding.userProfile.description": "この変更を承認すると、エージェントが今後の返信を調整できるようにオンボーディングプロフィールが更新されます。",
"tool.intervention.onboarding.userProfile.eyebrow": "オンボーディング承認",
"tool.intervention.onboarding.userProfile.fullName": "氏名",
"tool.intervention.onboarding.userProfile.responseLanguage": "応答言語",
"tool.intervention.onboarding.userProfile.title": "プロフィール更新の確認",
"tool.intervention.pending": "保留中",
"tool.intervention.reject": "拒否",
"tool.intervention.rejectAndContinue": "拒否して続行",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Ollama 設定が正しくありません。設定を確認してから再試行してください",
"response.InvalidProviderAPIKey": "{{provider}} API Key が空または正しくありません。{{provider}} API Key を確認してから再試行してください",
"response.InvalidVertexCredentials": "Vertex 認証に失敗しました。認証情報を確認してから再試行してください",
"response.LobeHubModelDeprecated": "モデル「{{model}}」はもう利用できません。モデルセレクターから現在のモデルを選択してください。",
"response.LocationNotSupportError": "現在の地域ではこのモデルサービスはサポートされていません(地域制限またはサービス未开通)。利用可能な地域に切り替えるか、別のモデルプロバイダーに変更してから再試行してください",
"response.ModelNotFound": "利用可能なモデルが見つからないかアクセス権限がありません。API キーを切り替えるか、権限を調整してから再試行してください",
"response.NoOpenAIAPIKey": "OpenAI API Key が空または正しくありません。カスタム OpenAI API キーを追加してください",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "{{provider}}に接続",
"action.connect.error": "接続に失敗しました。もう一度お試しください。",
"action.connect.popupBlocked": "接続ポップアップがブロックされました。続行するには、ブラウザでポップアップを許可してください。",
"action.create.error": "タスクの作成に失敗しました。もう一度お試しください。",
"action.create.success": "スケジュールされたタスクが追加されました。Lobe AIで確認してください。",
"action.createButton": "スケジュールされたタスクとして追加",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "トークン消費",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "このタスクを実行するための詳細な指示を入力してください...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "タスクのタイトルを入力してください...",
"agentMarketplace.category.businessStrategy": "ビジネスと戦略",
"agentMarketplace.category.contentCreation": "コンテンツ作成",
"agentMarketplace.category.creatorEconomy": "クリエイター経済",
"agentMarketplace.category.designCreative": "デザインとクリエイティブ",
"agentMarketplace.category.engineering": "エンジニアリング",
"agentMarketplace.category.financeLegal": "財務と法務",
"agentMarketplace.category.learningResearch": "学習と研究",
"agentMarketplace.category.marketing": "マーケティング",
"agentMarketplace.category.operations": "オペレーション",
"agentMarketplace.category.peopleHR": "人事とHR",
"agentMarketplace.category.personalLife": "個人生活",
"agentMarketplace.category.productManagement": "プロダクトマネジメント",
"agentMarketplace.category.salesCustomer": "営業と顧客",
"agentMarketplace.picker.empty": "テンプレートがありません。",
"agentMarketplace.picker.failedToLoad": "テンプレートの読み込みに失敗しました。後でもう一度お試しください。",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} テンプレートが利用可能です。",
"codeInterpreter-legacy.error": "実行エラー",
"codeInterpreter-legacy.executing": "実行中...",
"codeInterpreter-legacy.files": "ファイル:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "현재 온보딩 에이전트",
"tool.intervention.onboarding.agentIdentity.targets": "적용 대상",
"tool.intervention.onboarding.agentIdentity.title": "에이전트 프로필 업데이트 확인",
"tool.intervention.onboarding.userProfile.applyHint": "이 세부 정보는 승인 후 프로필에 저장됩니다.",
"tool.intervention.onboarding.userProfile.description": "이 변경 사항을 승인하면 온보딩 프로필이 업데이트되어 에이전트가 향후 응답을 맞춤화할 수 있습니다.",
"tool.intervention.onboarding.userProfile.eyebrow": "온보딩 승인",
"tool.intervention.onboarding.userProfile.fullName": "전체 이름",
"tool.intervention.onboarding.userProfile.responseLanguage": "응답 언어",
"tool.intervention.onboarding.userProfile.title": "프로필 업데이트 확인",
"tool.intervention.pending": "대기 중",
"tool.intervention.reject": "거부",
"tool.intervention.rejectAndContinue": "거부 후 계속",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Ollama 설정이 올바르지 않습니다. 설정을 확인한 후 다시 시도하세요",
"response.InvalidProviderAPIKey": "{{provider}} API Key가 비어 있거나 올바르지 않습니다. {{provider}} API Key를 확인한 후 다시 시도하세요",
"response.InvalidVertexCredentials": "Vertex 인증에 실패했습니다. 인증 정보를 확인한 후 다시 시도하세요",
"response.LobeHubModelDeprecated": "모델 \"{{model}}\"은(는) 더 이상 사용할 수 없습니다. 모델 선택기에서 현재 사용 가능한 모델을 선택해 주세요.",
"response.LocationNotSupportError": "현재 지역에서는 이 모델 서비스가 지원되지 않습니다(지역 제한 또는 서비스 미개통). 지원 가능한 지역으로 전환하거나 다른 모델 제공자로 변경한 후 다시 시도하세요",
"response.ModelNotFound": "사용 가능한 모델을 찾을 수 없거나 액세스 권한이 없습니다. API 키를 전환하거나 권한을 조정한 후 다시 시도하세요",
"response.NoOpenAIAPIKey": "OpenAI API Key가 비어 있거나 올바르지 않습니다. 사용자 정의 OpenAI API Key를 추가하세요",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "{{provider}} 연결",
"action.connect.error": "연결에 실패했습니다. 다시 시도해 주세요.",
"action.connect.popupBlocked": "연결 팝업이 차단되었습니다. 계속하려면 브라우저에서 팝업을 허용하세요.",
"action.create.error": "작업 생성에 실패했습니다. 다시 시도해 주세요.",
"action.create.success": "예약된 작업이 추가되었습니다. Lobe AI에서 확인하세요.",
"action.createButton": "예약된 작업으로 추가",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "토큰 사용량",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "이 작업을 수행하기 위한 에이전트의 자세한 지침...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "작업 제목...",
"agentMarketplace.category.businessStrategy": "비즈니스 및 전략",
"agentMarketplace.category.contentCreation": "콘텐츠 제작",
"agentMarketplace.category.creatorEconomy": "크리에이터 경제",
"agentMarketplace.category.designCreative": "디자인 및 창작",
"agentMarketplace.category.engineering": "엔지니어링",
"agentMarketplace.category.financeLegal": "재무 및 법률",
"agentMarketplace.category.learningResearch": "학습 및 연구",
"agentMarketplace.category.marketing": "마케팅",
"agentMarketplace.category.operations": "운영",
"agentMarketplace.category.peopleHR": "인사 및 HR",
"agentMarketplace.category.personalLife": "개인 생활",
"agentMarketplace.category.productManagement": "제품 관리",
"agentMarketplace.category.salesCustomer": "영업 및 고객",
"agentMarketplace.picker.empty": "사용 가능한 템플릿이 없습니다.",
"agentMarketplace.picker.failedToLoad": "템플릿을 불러오지 못했습니다. 나중에 다시 시도해 주세요.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}}개의 템플릿이 사용 가능합니다.",
"codeInterpreter-legacy.error": "실행 오류",
"codeInterpreter-legacy.executing": "실행 중...",
"codeInterpreter-legacy.files": "파일:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Huidige onboarding-agent",
"tool.intervention.onboarding.agentIdentity.targets": "Van toepassing op",
"tool.intervention.onboarding.agentIdentity.title": "Bevestig update van agentidentiteit",
"tool.intervention.onboarding.userProfile.applyHint": "Deze gegevens worden na goedkeuring aan je profiel toegevoegd.",
"tool.intervention.onboarding.userProfile.description": "Door deze wijziging goed te keuren, wordt je onboarding-profiel bijgewerkt zodat de Agent toekomstige antwoorden kan afstemmen.",
"tool.intervention.onboarding.userProfile.eyebrow": "Goedkeuring onboarding",
"tool.intervention.onboarding.userProfile.fullName": "Volledige naam",
"tool.intervention.onboarding.userProfile.responseLanguage": "Antwoordtaal",
"tool.intervention.onboarding.userProfile.title": "Bevestig je profielupdate",
"tool.intervention.pending": "In afwachting",
"tool.intervention.reject": "Afwijzen",
"tool.intervention.rejectAndContinue": "Afwijzen en opnieuw proberen",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Ongeldige Ollama-configuratie. Controleer de instellingen en probeer opnieuw.",
"response.InvalidProviderAPIKey": "{{provider}} API-sleutel is onjuist of leeg. Controleer je {{provider}} API-sleutel en probeer opnieuw.",
"response.InvalidVertexCredentials": "Vertex-authenticatie mislukt. Controleer je inloggegevens en probeer opnieuw.",
"response.LobeHubModelDeprecated": "Het model \"{{model}}\" is niet langer beschikbaar. Kies alstublieft een actueel model uit de modelkiezer.",
"response.LocationNotSupportError": "Sorry, je huidige locatie ondersteunt deze modelservice niet. Dit kan komen door regionale beperkingen. Controleer of je locatie wordt ondersteund of probeer een andere locatie.",
"response.ModelNotFound": "Sorry, het gevraagde model is niet gevonden. Het bestaat mogelijk niet of je hebt geen toegang. Probeer opnieuw met een andere API-sleutel of pas je rechten aan.",
"response.NoOpenAIAPIKey": "OpenAI API-sleutel is leeg. Voeg een aangepaste OpenAI API-sleutel toe.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "Verbind {{provider}}",
"action.connect.error": "Verbinding mislukt, probeer het alstublieft opnieuw.",
"action.connect.popupBlocked": "Verbindingspopup geblokkeerd. Sta pop-ups toe in uw browser om door te gaan.",
"action.create.error": "Taak aanmaken mislukt. Probeer het opnieuw.",
"action.create.success": "Geplande taak toegevoegd. Vind het in Lobe AI.",
"action.createButton": "Toevoegen als geplande taak",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Tokengebruik",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Gedetailleerde instructie voor de agent om deze taak uit te voeren...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Taaktitel...",
"agentMarketplace.category.businessStrategy": "Business & Strategie",
"agentMarketplace.category.contentCreation": "Contentcreatie",
"agentMarketplace.category.creatorEconomy": "Creator Economie",
"agentMarketplace.category.designCreative": "Design & Creatief",
"agentMarketplace.category.engineering": "Techniek",
"agentMarketplace.category.financeLegal": "Financiën & Juridisch",
"agentMarketplace.category.learningResearch": "Leren & Onderzoek",
"agentMarketplace.category.marketing": "Marketing",
"agentMarketplace.category.operations": "Operaties",
"agentMarketplace.category.peopleHR": "Mensen & HR",
"agentMarketplace.category.personalLife": "Persoonlijk Leven",
"agentMarketplace.category.productManagement": "Productbeheer",
"agentMarketplace.category.salesCustomer": "Verkoop & Klant",
"agentMarketplace.picker.empty": "Geen sjablonen beschikbaar.",
"agentMarketplace.picker.failedToLoad": "Laden van sjablonen mislukt. Probeer het later opnieuw.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} sjablonen beschikbaar.",
"codeInterpreter-legacy.error": "Uitvoeringsfout",
"codeInterpreter-legacy.executing": "Bezig met uitvoeren...",
"codeInterpreter-legacy.files": "Bestanden:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Obecny agent w onboardingu",
"tool.intervention.onboarding.agentIdentity.targets": "Dotyczy",
"tool.intervention.onboarding.agentIdentity.title": "Potwierdź aktualizację tożsamości agenta",
"tool.intervention.onboarding.userProfile.applyHint": "Te dane zostaną zapisane w Twoim profilu po zatwierdzeniu.",
"tool.intervention.onboarding.userProfile.description": "Zatwierdzenie tej zmiany aktualizuje Twój profil onboardingowy, dzięki czemu Agent może dostosować przyszłe odpowiedzi.",
"tool.intervention.onboarding.userProfile.eyebrow": "Zatwierdzenie onboardingu",
"tool.intervention.onboarding.userProfile.fullName": "Pełne imię i nazwisko",
"tool.intervention.onboarding.userProfile.responseLanguage": "Język odpowiedzi",
"tool.intervention.onboarding.userProfile.title": "Potwierdź aktualizację swojego profilu",
"tool.intervention.pending": "Oczekujące",
"tool.intervention.reject": "Odrzuć",
"tool.intervention.rejectAndContinue": "Odrzuć i spróbuj ponownie",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Nieprawidłowa konfiguracja Ollama. Sprawdź ustawienia i spróbuj ponownie.",
"response.InvalidProviderAPIKey": "Nieprawidłowy lub pusty klucz API dla {{provider}}. Sprawdź i spróbuj ponownie.",
"response.InvalidVertexCredentials": "Uwierzytelnienie Vertex nie powiodło się. Sprawdź dane logowania i spróbuj ponownie.",
"response.LobeHubModelDeprecated": "Model \"{{model}}\" nie jest już dostępny. Proszę wybrać aktualny model z selektora modeli.",
"response.LocationNotSupportError": "Przepraszamy, Twoja lokalizacja nie obsługuje tej usługi. Może to wynikać z ograniczeń regionalnych. Sprawdź dostępność usługi lub spróbuj z innej lokalizacji.",
"response.ModelNotFound": "Przepraszamy, nie znaleziono żądanego modelu. Może nie istnieć lub nie masz do niego dostępu. Spróbuj ponownie z innym kluczem API lub zmień uprawnienia.",
"response.NoOpenAIAPIKey": "Brak klucza OpenAI API. Dodaj własny klucz, aby kontynuować.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "Połącz z {{provider}}",
"action.connect.error": "Połączenie nie powiodło się, spróbuj ponownie.",
"action.connect.popupBlocked": "Wyskakujące okienko połączenia zostało zablokowane. Zezwól na wyskakujące okienka w przeglądarce, aby kontynuować.",
"action.create.error": "Nie udało się utworzyć zadania. Spróbuj ponownie.",
"action.create.success": "Dodano zaplanowane zadanie. Znajdziesz je w Lobe AI.",
"action.createButton": "Dodaj jako zaplanowane zadanie",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Zużycie Tokenów",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Szczegółowa instrukcja dla agenta do wykonania tego zadania...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Tytuł zadania...",
"agentMarketplace.category.businessStrategy": "Biznes i Strategia",
"agentMarketplace.category.contentCreation": "Tworzenie Treści",
"agentMarketplace.category.creatorEconomy": "Ekonomia Twórców",
"agentMarketplace.category.designCreative": "Projektowanie i Kreatywność",
"agentMarketplace.category.engineering": "Inżynieria",
"agentMarketplace.category.financeLegal": "Finanse i Prawo",
"agentMarketplace.category.learningResearch": "Nauka i Badania",
"agentMarketplace.category.marketing": "Marketing",
"agentMarketplace.category.operations": "Operacje",
"agentMarketplace.category.peopleHR": "Zasoby Ludzkie i HR",
"agentMarketplace.category.personalLife": "Życie Osobiste",
"agentMarketplace.category.productManagement": "Zarządzanie Produktem",
"agentMarketplace.category.salesCustomer": "Sprzedaż i Obsługa Klienta",
"agentMarketplace.picker.empty": "Brak dostępnych szablonów.",
"agentMarketplace.picker.failedToLoad": "Nie udało się załadować szablonów. Spróbuj ponownie później.",
"agentMarketplace.picker.summary": "Dostępne szablony: {{filtered}} z {{total}}.",
"codeInterpreter-legacy.error": "Błąd Wykonania",
"codeInterpreter-legacy.executing": "Wykonywanie...",
"codeInterpreter-legacy.files": "Pliki:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Agente atual de onboarding",
"tool.intervention.onboarding.agentIdentity.targets": "Aplica-se a",
"tool.intervention.onboarding.agentIdentity.title": "Confirmar atualização de identidade do agente",
"tool.intervention.onboarding.userProfile.applyHint": "Esses detalhes serão salvos no seu perfil após aprovação.",
"tool.intervention.onboarding.userProfile.description": "A aprovação desta alteração atualiza seu perfil de integração para que o Agente possa personalizar respostas futuras.",
"tool.intervention.onboarding.userProfile.eyebrow": "Aprovação de integração",
"tool.intervention.onboarding.userProfile.fullName": "Nome completo",
"tool.intervention.onboarding.userProfile.responseLanguage": "Idioma de resposta",
"tool.intervention.onboarding.userProfile.title": "Confirme a atualização do seu perfil",
"tool.intervention.pending": "Pendente",
"tool.intervention.reject": "Rejeitar",
"tool.intervention.rejectAndContinue": "Rejeitar e Tentar Novamente",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Configuração inválida do Ollama. Verifique e tente novamente.",
"response.InvalidProviderAPIKey": "A chave de API do {{provider}} está incorreta ou vazia. Verifique e tente novamente.",
"response.InvalidVertexCredentials": "Falha na autenticação do Vertex. Verifique suas credenciais e tente novamente.",
"response.LobeHubModelDeprecated": "O modelo \"{{model}}\" não está mais disponível. Por favor, escolha um modelo atual no seletor de modelos.",
"response.LocationNotSupportError": "Desculpe, sua localização atual não suporta este serviço. Verifique as restrições regionais ou tente de outro local.",
"response.ModelNotFound": "Desculpe, o modelo solicitado não foi encontrado. Verifique se ele existe ou se você tem permissão de acesso.",
"response.NoOpenAIAPIKey": "A chave de API do OpenAI está vazia. Adicione uma chave personalizada.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "Conectar {{provider}}",
"action.connect.error": "Conexão falhou, por favor tente novamente.",
"action.connect.popupBlocked": "Popup de conexão bloqueado. Permita popups no seu navegador para continuar.",
"action.create.error": "Falha ao criar a tarefa. Por favor, tente novamente.",
"action.create.success": "Tarefa agendada adicionada. Encontre-a no Lobe AI.",
"action.createButton": "Adicionar como tarefa agendada",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Uso de Tokens",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Instruções detalhadas para o agente executar esta tarefa...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Título da tarefa...",
"agentMarketplace.category.businessStrategy": "Negócios e Estratégia",
"agentMarketplace.category.contentCreation": "Criação de Conteúdo",
"agentMarketplace.category.creatorEconomy": "Economia do Criador",
"agentMarketplace.category.designCreative": "Design e Criatividade",
"agentMarketplace.category.engineering": "Engenharia",
"agentMarketplace.category.financeLegal": "Finanças e Jurídico",
"agentMarketplace.category.learningResearch": "Aprendizado e Pesquisa",
"agentMarketplace.category.marketing": "Marketing",
"agentMarketplace.category.operations": "Operações",
"agentMarketplace.category.peopleHR": "Pessoas e RH",
"agentMarketplace.category.personalLife": "Vida Pessoal",
"agentMarketplace.category.productManagement": "Gestão de Produto",
"agentMarketplace.category.salesCustomer": "Vendas e Atendimento ao Cliente",
"agentMarketplace.picker.empty": "Nenhum modelo disponível.",
"agentMarketplace.picker.failedToLoad": "Falha ao carregar modelos. Por favor, tente novamente mais tarde.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} modelos disponíveis.",
"codeInterpreter-legacy.error": "Erro de Execução",
"codeInterpreter-legacy.executing": "Executando...",
"codeInterpreter-legacy.files": "Arquivos:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Текущий онбординговый агент",
"tool.intervention.onboarding.agentIdentity.targets": "Применяется к",
"tool.intervention.onboarding.agentIdentity.title": "Подтвердите обновление личности агента",
"tool.intervention.onboarding.userProfile.applyHint": "Эти данные будут сохранены в вашем профиле после одобрения.",
"tool.intervention.onboarding.userProfile.description": "Одобрение этого изменения обновит ваш профиль, чтобы Агент мог адаптировать будущие ответы.",
"tool.intervention.onboarding.userProfile.eyebrow": "Одобрение профиля",
"tool.intervention.onboarding.userProfile.fullName": "Полное имя",
"tool.intervention.onboarding.userProfile.responseLanguage": "Язык ответа",
"tool.intervention.onboarding.userProfile.title": "Подтвердите обновление вашего профиля",
"tool.intervention.pending": "В ожидании",
"tool.intervention.reject": "Отклонить",
"tool.intervention.rejectAndContinue": "Отклонить и повторить",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Некорректная конфигурация Ollama. Проверьте настройки и повторите попытку.",
"response.InvalidProviderAPIKey": "Неверный или пустой API-ключ для {{provider}}. Проверьте ключ и повторите попытку.",
"response.InvalidVertexCredentials": "Ошибка аутентификации Vertex. Проверьте данные и повторите попытку.",
"response.LobeHubModelDeprecated": "Модель \"{{model}}\" больше недоступна. Пожалуйста, выберите актуальную модель из списка моделей.",
"response.LocationNotSupportError": "Извините, в вашем регионе эта модель недоступна. Попробуйте использовать другой регион.",
"response.ModelNotFound": "Извините, модель не найдена. Возможно, она не существует или у вас нет доступа. Попробуйте изменить API-ключ или настройки доступа.",
"response.NoOpenAIAPIKey": "API-ключ OpenAI не указан. Пожалуйста, добавьте пользовательский ключ.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "Подключить {{provider}}",
"action.connect.error": "Не удалось подключиться, пожалуйста, попробуйте снова.",
"action.connect.popupBlocked": "Всплывающее окно подключения заблокировано. Разрешите всплывающие окна в вашем браузере, чтобы продолжить.",
"action.create.error": "Не удалось создать задачу. Пожалуйста, попробуйте снова.",
"action.create.success": "Запланированная задача добавлена. Найдите её в Lobe AI.",
"action.createButton": "Добавить как запланированную задачу",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Использование токенов",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Подробная инструкция для агента по выполнению этой задачи...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Название задачи...",
"agentMarketplace.category.businessStrategy": "Бизнес и стратегия",
"agentMarketplace.category.contentCreation": "Создание контента",
"agentMarketplace.category.creatorEconomy": "Экономика создателей",
"agentMarketplace.category.designCreative": "Дизайн и креатив",
"agentMarketplace.category.engineering": "Инженерия",
"agentMarketplace.category.financeLegal": "Финансы и право",
"agentMarketplace.category.learningResearch": "Обучение и исследования",
"agentMarketplace.category.marketing": "Маркетинг",
"agentMarketplace.category.operations": "Операции",
"agentMarketplace.category.peopleHR": "Персонал и HR",
"agentMarketplace.category.personalLife": "Личная жизнь",
"agentMarketplace.category.productManagement": "Управление продуктом",
"agentMarketplace.category.salesCustomer": "Продажи и клиенты",
"agentMarketplace.picker.empty": "Шаблоны отсутствуют.",
"agentMarketplace.picker.failedToLoad": "Не удалось загрузить шаблоны. Пожалуйста, попробуйте позже.",
"agentMarketplace.picker.summary": "Доступно шаблонов: {{filtered}} из {{total}}.",
"codeInterpreter-legacy.error": "Ошибка выполнения",
"codeInterpreter-legacy.executing": "Выполнение...",
"codeInterpreter-legacy.files": "Файлы:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Geçerli onboarding Ajanı",
"tool.intervention.onboarding.agentIdentity.targets": "Uygulanan yerler",
"tool.intervention.onboarding.agentIdentity.title": "Ajan kimliği güncellemesini onayla",
"tool.intervention.onboarding.userProfile.applyHint": "Bu bilgiler onaylandıktan sonra profilinize kaydedilecektir.",
"tool.intervention.onboarding.userProfile.description": "Bu değişikliği onaylamak, temsilcinin gelecekteki yanıtları kişiselleştirebilmesi için giriş profilinizi günceller.",
"tool.intervention.onboarding.userProfile.eyebrow": "Giriş onayı",
"tool.intervention.onboarding.userProfile.fullName": "Tam ad",
"tool.intervention.onboarding.userProfile.responseLanguage": "Yanıt dili",
"tool.intervention.onboarding.userProfile.title": "Profil güncellemenizi onaylayın",
"tool.intervention.pending": "Beklemede",
"tool.intervention.reject": "Reddet",
"tool.intervention.rejectAndContinue": "Reddet ve Yeniden Dene",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Geçersiz Ollama yapılandırması. Lütfen ayarları kontrol edip tekrar deneyin.",
"response.InvalidProviderAPIKey": "{{provider}} API Anahtarı hatalı veya boş. Lütfen kontrol edip tekrar deneyin.",
"response.InvalidVertexCredentials": "Vertex kimlik doğrulaması başarısız oldu. Lütfen bilgilerinizi kontrol edip tekrar deneyin.",
"response.LobeHubModelDeprecated": "\"{{model}}\" modeli artık mevcut değil. Lütfen model seçicisinden güncel bir model seçin.",
"response.LocationNotSupportError": "Üzgünüz, bulunduğunuz konum bu model hizmetini desteklemiyor. Bu, bölgesel kısıtlamalardan veya hizmetin mevcut olmamasından kaynaklanabilir. Lütfen konumunuzu kontrol edin veya farklı bir konumdan deneyin.",
"response.ModelNotFound": "Üzgünüz, istenen model bulunamadı. Model mevcut olmayabilir veya gerekli erişim izinlerine sahip olmayabilirsiniz. Lütfen API Anahtarınızı değiştirip tekrar deneyin.",
"response.NoOpenAIAPIKey": "OpenAI API Anahtarı boş. Lütfen özel bir OpenAI API Anahtarı ekleyin.",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "{{provider}} bağla",
"action.connect.error": "Bağlantı başarısız oldu, lütfen tekrar deneyin.",
"action.connect.popupBlocked": "Bağlantı açılır penceresi engellendi. Devam etmek için tarayıcınızda açılır pencerelere izin verin.",
"action.create.error": "Görev oluşturulamadı. Lütfen tekrar deneyin.",
"action.create.success": "Zamanlanmış görev eklendi. Lobe AIde bulabilirsiniz.",
"action.createButton": "Zamanlanmış görev olarak ekle",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Token Kullanımı",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Bu görevi gerçekleştirmesi için ajana verilecek detaylı talimat...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Görev başlığı...",
"agentMarketplace.category.businessStrategy": "İş ve Strateji",
"agentMarketplace.category.contentCreation": "İçerik Oluşturma",
"agentMarketplace.category.creatorEconomy": "Yaratıcı Ekonomi",
"agentMarketplace.category.designCreative": "Tasarım ve Yaratıcılık",
"agentMarketplace.category.engineering": "Mühendislik",
"agentMarketplace.category.financeLegal": "Finans ve Hukuk",
"agentMarketplace.category.learningResearch": "Öğrenme ve Araştırma",
"agentMarketplace.category.marketing": "Pazarlama",
"agentMarketplace.category.operations": "Operasyonlar",
"agentMarketplace.category.peopleHR": "İnsan Kaynakları",
"agentMarketplace.category.personalLife": "Kişisel Yaşam",
"agentMarketplace.category.productManagement": "Ürün Yönetimi",
"agentMarketplace.category.salesCustomer": "Satış ve Müşteri",
"agentMarketplace.picker.empty": "Şablon bulunmamaktadır.",
"agentMarketplace.picker.failedToLoad": "Şablonlar yüklenemedi. Lütfen daha sonra tekrar deneyin.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} şablon mevcut.",
"codeInterpreter-legacy.error": "Yürütme Hatası",
"codeInterpreter-legacy.executing": "Yürütülüyor...",
"codeInterpreter-legacy.files": "Dosyalar:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "Tác tử Onboarding hiện tại",
"tool.intervention.onboarding.agentIdentity.targets": "Áp dụng cho",
"tool.intervention.onboarding.agentIdentity.title": "Xác nhận cập nhật danh tính Tác tử",
"tool.intervention.onboarding.userProfile.applyHint": "Những thông tin này sẽ được lưu vào hồ sơ của bạn sau khi được phê duyệt.",
"tool.intervention.onboarding.userProfile.description": "Phê duyệt thay đổi này sẽ cập nhật hồ sơ giới thiệu của bạn để Đại lý có thể điều chỉnh các phản hồi trong tương lai.",
"tool.intervention.onboarding.userProfile.eyebrow": "Phê duyệt giới thiệu",
"tool.intervention.onboarding.userProfile.fullName": "Họ và tên",
"tool.intervention.onboarding.userProfile.responseLanguage": "Ngôn ngữ phản hồi",
"tool.intervention.onboarding.userProfile.title": "Xác nhận cập nhật hồ sơ của bạn",
"tool.intervention.pending": "Đang chờ xử lý",
"tool.intervention.reject": "Từ chối",
"tool.intervention.rejectAndContinue": "Từ chối và thử lại",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Cấu hình Ollama không hợp lệ, vui lòng kiểm tra và thử lại.",
"response.InvalidProviderAPIKey": "API Key của {{provider}} không hợp lệ hoặc để trống, vui lòng kiểm tra và thử lại.",
"response.InvalidVertexCredentials": "Xác thực Vertex thất bại. Vui lòng kiểm tra thông tin xác thực và thử lại.",
"response.LobeHubModelDeprecated": "Mô hình \"{{model}}\" không còn khả dụng. Vui lòng chọn một mô hình hiện tại từ bộ chọn mô hình.",
"response.LocationNotSupportError": "Xin lỗi, vị trí hiện tại của bạn không hỗ trợ dịch vụ mô hình này. Có thể do hạn chế khu vực hoặc dịch vụ chưa khả dụng. Vui lòng kiểm tra hoặc thử từ vị trí khác.",
"response.ModelNotFound": "Xin lỗi, không tìm thấy mô hình yêu cầu. Có thể mô hình không tồn tại hoặc bạn không có quyền truy cập. Vui lòng thử lại với API Key khác hoặc điều chỉnh quyền truy cập.",
"response.NoOpenAIAPIKey": "OpenAI API Key đang để trống, vui lòng thêm API Key tùy chỉnh",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "Kết nối {{provider}}",
"action.connect.error": "Kết nối thất bại, vui lòng thử lại.",
"action.connect.popupBlocked": "Cửa sổ bật lên kết nối bị chặn. Cho phép cửa sổ bật lên trong trình duyệt của bạn để tiếp tục.",
"action.create.error": "Không thể tạo nhiệm vụ. Vui lòng thử lại.",
"action.create.success": "Đã thêm nhiệm vụ đã lên lịch. Tìm nó trong Lobe AI.",
"action.createButton": "Thêm làm nhiệm vụ đã lên lịch",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Sử dụng token",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "Hướng dẫn chi tiết để tác nhân thực hiện nhiệm vụ này...",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "Tiêu đề nhiệm vụ...",
"agentMarketplace.category.businessStrategy": "Kinh doanh & Chiến lược",
"agentMarketplace.category.contentCreation": "Sáng tạo Nội dung",
"agentMarketplace.category.creatorEconomy": "Kinh tế Sáng tạo",
"agentMarketplace.category.designCreative": "Thiết kế & Sáng tạo",
"agentMarketplace.category.engineering": "Kỹ thuật",
"agentMarketplace.category.financeLegal": "Tài chính & Pháp lý",
"agentMarketplace.category.learningResearch": "Học tập & Nghiên cứu",
"agentMarketplace.category.marketing": "Tiếp thị",
"agentMarketplace.category.operations": "Vận hành",
"agentMarketplace.category.peopleHR": "Nhân sự & HR",
"agentMarketplace.category.personalLife": "Cuộc sống Cá nhân",
"agentMarketplace.category.productManagement": "Quản lý Sản phẩm",
"agentMarketplace.category.salesCustomer": "Bán hàng & Khách hàng",
"agentMarketplace.picker.empty": "Không có mẫu nào khả dụng.",
"agentMarketplace.picker.failedToLoad": "Không tải được mẫu. Vui lòng thử lại sau.",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} mẫu khả dụng.",
"codeInterpreter-legacy.error": "Lỗi thực thi",
"codeInterpreter-legacy.executing": "Đang thực thi...",
"codeInterpreter-legacy.files": "Tệp:",
+16
View File
@@ -599,6 +599,7 @@
"taskSchedule.scheduleType.weekly": "每周",
"taskSchedule.scheduler": "定时任务",
"taskSchedule.schedulerTab": "定时任务",
"taskSchedule.startScheduling": "启动定时",
"taskSchedule.summary.daily": "每天 {{time}} 运行",
"taskSchedule.summary.disabled": "自动化未启用",
"taskSchedule.summary.everyNHours": "每 {{count}} 小时{{minute}}",
@@ -667,6 +668,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "当前 onboarding Agent",
"tool.intervention.onboarding.agentIdentity.targets": "应用范围",
"tool.intervention.onboarding.agentIdentity.title": "确认 Agent 名称与头像",
"tool.intervention.onboarding.userProfile.applyHint": "这些信息将在批准后保存到您的个人资料中。",
"tool.intervention.onboarding.userProfile.description": "批准此更改将更新您的入职资料,以便代理可以定制未来的回复。",
"tool.intervention.onboarding.userProfile.eyebrow": "入职批准",
"tool.intervention.onboarding.userProfile.fullName": "全名",
"tool.intervention.onboarding.userProfile.responseLanguage": "回复语言",
"tool.intervention.onboarding.userProfile.title": "确认您的资料更新",
"tool.intervention.pending": "等待中",
"tool.intervention.reject": "拒绝",
"tool.intervention.rejectAndContinue": "拒绝后继续",
@@ -826,6 +833,15 @@
"workingPanel.resources.renameSuccess": "重命名成功",
"workingPanel.resources.viewMode.list": "列表视图",
"workingPanel.resources.viewMode.tree": "树状视图",
"workingPanel.review.binary": "二进制文件,无法展示 diff",
"workingPanel.review.empty": "工作区没有未提交的变更",
"workingPanel.review.error": "无法加载该文件的 diff",
"workingPanel.review.title": "审查",
"workingPanel.review.tooLarge": "文件过大,未在面板内展示 diff",
"workingPanel.review.unstaged": "未暂存",
"workingPanel.review.viewMode.split": "切换到双栏对比",
"workingPanel.review.viewMode.unified": "切换到合并视图",
"workingPanel.space": "空间",
"workingPanel.title": "工作面板",
"you": "你",
"zenMode": "专注模式"
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Ollama 配置不正确。请检查配置后重试",
"response.InvalidProviderAPIKey": "{{provider}} API Key 为空或不正确,请检查 {{provider}} API Key 后重试",
"response.InvalidVertexCredentials": "Vertex 鉴权失败。请检查凭证后重试",
"response.LobeHubModelDeprecated": "模型「{{model}}」已下架,请到模型选择器中重新选择可用模型。",
"response.LocationNotSupportError": "当前地区暂不支持该模型服务(可能受区域限制或服务未开通)。请切换可用地区或更换模型服务商后重试",
"response.ModelNotFound": "未找到可用模型或无访问权限。请更换 API Key 或调整权限后重试",
"response.NoOpenAIAPIKey": "OpenAI API Key 为空或不正确,请添加自定义 OpenAI API Key",
+2 -86
View File
@@ -1,7 +1,7 @@
{
"action.connect.button": "连接 {{provider}}",
"action.connect.error": "连接失败,请稍后再试",
"action.connect.popupBlocked": "连接弹窗被浏览器拦截,请允许弹窗后重试",
"action.connect.error": "连接失败,请重试。",
"action.connect.popupBlocked": "连接弹出窗口被阻止。请在浏览器中允许弹出窗口以继续。",
"action.create.error": "创建任务失败,请稍后再试",
"action.create.success": "定时任务已创建,可在 Lobe AI 中查看",
"action.createButton": "添加为定时任务",
@@ -11,339 +11,255 @@
"action.optionalConnect.button": "连接 {{provider}} 获取更丰富的内容",
"ad-creative-inspiration.description": "每天扫一遍竞品和标杆品牌的新广告素材(Meta / Google Ads Library),挖能复刻的 10 条",
"ad-creative-inspiration.prompt": "每天早上 10:00 扫一遍我的竞品和标杆品牌在 Meta 和 Google Ads Library 上的新素材,挑出 10 条值得复刻的,并说明每条值得的理由。",
"ad-creative-inspiration.title": "投放素材灵感",
"aigc-prompt-inspiration.description": "每天 5 组精选 PromptMidjourney / SD / Flux),按风格分类,今天就能试",
"aigc-prompt-inspiration.prompt": "每天早上 10:00 给我 5 组精选 PromptMidjourney / Stable Diffusion / Flux),按风格分类,每条都要可以直接复制使用。",
"aigc-prompt-inspiration.title": "AIGC Prompt 灵感",
"arxiv-curated-daily.description": "每天早上帮你筛 5 篇最新论文 + 一句话摘要,刷论文时间省一半",
"arxiv-curated-daily.prompt": "每天早上 9:00 帮我从 arXiv 筛 5 篇和我研究方向相关的最新论文,每篇附一句话摘要,帮我判断哪些值得精读。",
"arxiv-curated-daily.title": "ArXiv 精选",
"bedtime-gratitude.description": "每天 22 点引导你写下今天三件感谢的事 + 学到的一件事,沉淀进笔记",
"bedtime-gratitude.prompt": "每天晚上 22:00 引导我写下今天三件感谢的事和学到的一件事,回我一段温柔的小结。如果连接了 Notion,把这条感恩记录追加到我的日记页。",
"bedtime-gratitude.title": "睡前感恩",
"brand-collab-weekly.description": "每周一扫一遍正在找创作者的品牌和公开招募,匹配你的领域和粉丝规模",
"brand-collab-weekly.prompt": "每周一早上 10:00 扫一遍正在公开招募创作者的品牌,按我的赛道和粉丝量匹配,挑出 5 个值得申请的机会。",
"brand-collab-weekly.title": "品牌合作机会",
"brand-mention-daily.description": "告诉我要追踪的品牌 / 关键词,每天傍晚汇总当天提及量、情绪、热门发言者",
"brand-mention-daily.prompt": "每天傍晚 18:00 在 X (Twitter) 上汇总我追踪的品牌和关键词当天的提及量、情绪、TOP 发言者,标出异常波动。",
"brand-mention-daily.title": "品牌声量日报",
"brand-watch-weekly.description": "每周一追踪 10 家大厂品牌升级、Logo 改版、官网重设计,附拆解视角",
"brand-watch-weekly.prompt": "每周一早上 10:00 追踪 10 家我关注的品牌动态:品牌升级、Logo 改版、官网重设计,每条附一段拆解。",
"brand-watch-weekly.title": "大厂品牌动态",
"calendar-conflict-check.description": "每天早上检查日程有没有冲突、间隔太紧、通勤不够",
"calendar-conflict-check.prompt": "每天早上 7:30 检查我今天的日历,找出冲突、连背靠背会议、通勤或缓冲时间不够的情况,给出建议调整方案。",
"calendar-conflict-check.title": "日历冲突检查",
"cashflow-weekly.description": "每周一扫一下本周该收的款、该付的账、下周大额支出预警",
"cashflow-weekly.prompt": "每周一早上 9:00 扫一遍本周应收款、应付账,并预警下周的大额支出。",
"cashflow-weekly.title": "现金流周报",
"child-growth-weekly.description": "告诉我孩子年龄,每周一给你本周发育重点、亲子活动建议、注意事项",
"child-growth-weekly.prompt": "每周一早上 9:00 根据我孩子的年龄,给出本周的发育重点、亲子活动建议和需要留心的注意事项。",
"child-growth-weekly.title": "孩子成长周报",
"child-study-weekly.description": "告诉我孩子在学的科目,每周日帮你回顾本周完成情况 + 下周重点",
"child-study-weekly.prompt": "每周日晚 20:00 回顾我孩子本周的学习进度,并梳理下周的学习重点,按科目给出练习建议。",
"child-study-weekly.title": "孩子学习追踪",
"competitor-creator-tracking.description": "告诉我 3-5 个你关注的创作者,每天看他们发了什么、数据怎样,挖能复刻的思路",
"competitor-creator-tracking.prompt": "每天早上 9:00 追踪我设定的 3-5 个对标创作者:他们发了什么内容、数据如何,挖出我可以复刻的思路。",
"competitor-creator-tracking.title": "竞品创作者追踪",
"competitor-radar-daily.description": "告诉我 3-5 个竞争对手,每天帮你盯他们的官网更新、产品发布、招聘信号、社媒动态",
"competitor-radar-daily.prompt": "每天早上 9:00 追踪我设定的 3-5 个竞争对手:官网更新、产品发布、招聘信号、社媒动态,分析每个动作的战略含义。",
"competitor-radar-daily.title": "竞品动态追踪",
"competitor-update-daily.description": "告诉我 3-5 个竞品,每天看他们的更新日志、新功能、官网变化",
"competitor-update-daily.prompt": "每天早上 10:00 监测 3-5 个竞品产品的更新:更新日志、新功能、官网文案变化,标出值得深入研究的信号。",
"competitor-update-daily.title": "竞品更新追踪",
"content-calendar-weekly.description": "每周日晚帮你规划下周 7 天的发布计划,对齐节日和热点节奏",
"content-calendar-weekly.prompt": "每周日晚 20:00 帮我规划下周 7 天的发布计划:把日程对齐近期节日和热点节奏,每个时段给一个建议选题。如果连接了 Notion,把这份计划同步成排期表。",
"content-calendar-weekly.title": "内容日历",
"contract-expiry-weekly.description": "每周一检查下个月到期的合同(订阅 / 租赁 / 合作),提前续签或解约",
"contract-expiry-weekly.prompt": "每周一早上 9:00 列出未来 30 天到期的合同(订阅、租赁、合作),标注哪些需要续签、哪些可以解约。",
"contract-expiry-weekly.title": "合同到期预警",
"core-metric-daily.description": "告诉我要看的指标(DAU、留存、转化),每天早上自动同步变化",
"core-metric-daily.prompt": "每天早上 9:00 同步我的核心指标变化(DAU、留存、转化),与昨天和 7 日均值做对比。",
"core-metric-daily.title": "核心指标日报",
"cross-platform-engagement-daily.description": "每天早上聚合你全平台的评论、私信、提及、新粉丝",
"cross-platform-engagement-daily.prompt": "每天早上 9:00 聚合我各平台的评论、私信、提及和新粉丝,标出 5 条最值得回复的。",
"cross-platform-engagement-daily.title": "全平台互动日报",
"crypto-market-daily.description": "每天早上看比特币、以太坊、你关注币种的 24h 变化 + 重要链上事件",
"crypto-market-daily.prompt": "每天早上 9:00 给我比特币、以太坊和我关注币种的 24h 价格变化,加上过去一天最重要的链上事件。",
"crypto-market-daily.title": "加密市场日报",
"daily-design-inspiration.description": "每天早上从 Dribbble、Behance、Awwwards、Pinterest 挑 10 个和你风格匹配的作品",
"daily-design-inspiration.prompt": "每天早上 9:00 从 Dribbble、Behance、Awwwards、Pinterest 挑 10 个和我风格匹配的作品,各附一句亮点点评。",
"daily-design-inspiration.title": "每日灵感",
"daily-followup-list.description": "每天早上按优先级排一遍今天该跟进的客户,附上次沟通要点",
"daily-followup-list.prompt": "每天早上 9:00 从 HubSpot 中排出今天该跟进的客户优先级清单,每条附上次沟通要点。",
"daily-followup-list.title": "今日跟进清单",
"daily-learning-bite.description": "每天给你一条 15 分钟能看完的学习内容(文章 / 视频 / 播客)",
"daily-learning-bite.prompt": "每天早上 7:30 给我一条 15 分钟能看完的学习内容(文章 / 视频 / 播客),附一句关键收获。",
"daily-learning-bite.title": "每日学习料",
"daily-topic-pick.description": "每天早上帮你扒一遍你赛道前一天跑得最好的 10 条内容,拆解选题角度",
"daily-topic-pick.prompt": "每天早上 9:00 帮我扒我赛道前一天跑得最好的 10 条内容,拆解选题角度,挑 1-2 个我今天能直接发的。",
"daily-topic-pick.title": "今日选题",
"deal-pipeline-weekly.description": "每周五盘点管道里所有 Deal:哪些推进、哪些停滞、本月能成多少",
"deal-pipeline-weekly.prompt": "每周五下午 16:00 盘点 HubSpot 管道里的所有 Deal:本周推进的、停滞的,并预测本月能成多少。",
"deal-pipeline-weekly.title": "Deal Pipeline 周报",
"dependency-security-weekly.description": "每周一自动扫一遍你项目的漏洞和过期版本,给出升级优先级",
"dependency-security-weekly.prompt": "每周一早上 10:00 扫一遍我 GitHub 项目里有漏洞或过期的依赖,按严重程度和升级风险排出优先级。",
"dependency-security-weekly.title": "依赖安全周检",
"design-trend-weekly.description": "每周一给你本周 UI / 品牌 / 插画 3 个新趋势 + 5 个代表案例",
"design-trend-weekly.prompt": "每周一早上 9:00 给我 UI、品牌、插画领域本周 3 个新趋势,每个趋势配 5 个代表案例。",
"design-trend-weekly.title": "设计趋势周报",
"diet-log-companion.description": "每天晚上帮你回顾今天吃了什么,给下次的调整建议。不强迫、不批判",
"diet-log-companion.prompt": "每天晚上 21:00 陪我回顾今天的饮食,温柔地给一两条明天可以调整的建议,不强迫、不批判。",
"diet-log-companion.title": "饮食记录陪跑",
"exhibition-event-weekly.description": "告诉我你所在城市,每周一给你本周的展览、演出、livehouse 信息",
"exhibition-event-weekly.prompt": "每周一早上 10:00 列出我所在城市本周的展览、演出、livehouse 演出信息,给出最值得去的几条简介。",
"exhibition-event-weekly.title": "展览演出日历",
"family-finance-weekly.description": "每周日晚回顾本周支出结构、预算完成度、下周大额计划",
"family-finance-weekly.prompt": "每周日晚 20:00 基于 Google Sheets 流水回顾本周家庭支出结构、预算完成度,并预告下周的大额支出计划。",
"family-finance-weekly.title": "家庭财务周报",
"family-task-schedule.description": "每周一早上分配本周家务、采购、接送、缴费,家庭群可同步",
"family-task-schedule.prompt": "每周一早上 8:00 帮我排好本周家庭任务计划:家务、采购、接送、缴费,给每项一个暂定责任人和时间段。如果连接了 Google Calendar,建议可直接落进日程的时间块。",
"family-task-schedule.title": "家庭任务排期",
"figma-files-cleanup.description": "每周五下班前帮你盘点近期更新的 Figma 文件,标记该归档的、该同步开发的",
"figma-files-cleanup.prompt": "每周五下午 17:00 盘点近期更新的 Figma 文件,标记哪些该归档、哪些需要同步给开发,还有哪些需要继续打磨。",
"figma-files-cleanup.title": "Figma 文件整理",
"follower-growth-weekly.description": "每周一看跨平台的粉丝变化:哪个平台在涨、哪个在跌、该加码哪里",
"follower-growth-weekly.prompt": "每周一早上 10:00 回顾我 X (Twitter) 等平台的粉丝增长,标出该加码的平台和互动下滑的平台。",
"follower-growth-weekly.title": "粉丝增长周报",
"font-color-weekly.description": "每周三给你 3 组值得收藏的字体组合 + 3 组配色方案,直接存进灵感库",
"font-color-weekly.prompt": "每周三早上 10:00 给我 3 组值得收藏的字体组合和 3 组配色方案,每组字体附授权或下载渠道。",
"font-color-weekly.title": "字体配色周报",
"friday-wrap-list.description": "每周五下午列一份:这周没做完的、周一要交付的、下周第一件事",
"friday-wrap-list.prompt": "每周五下午 16:00 列一份:本周没做完的、周一要交付的、下周第一件事。",
"friday-wrap-list.title": "周五收尾清单",
"funding-intel-daily.description": "每天给你 3-5 条你赛道的融资快讯:谁拿钱、估值多少、投资人是谁",
"funding-intel-daily.prompt": "每天早上 10:00 给我赛道里过去 24 小时的 3-5 条融资快讯:谁拿了钱、金额、估值、领投方。",
"funding-intel-daily.title": "融资情报日报",
"headline-inspiration.description": "每天给你 10 个符合你调性的标题模板,从近期爆款反推的结构",
"headline-inspiration.prompt": "每天早上 10:00 从近期爆款反推 10 个符合我调性的标题模板,卡标题时直接抄。",
"headline-inspiration.title": "标题灵感",
"hot-topic-radar.description": "每天早上一次性看完你领域里正在升温的 5 个话题,趁还没挤满就能下手",
"hot-topic-radar.prompt": "每天早上 10:00 给我我赛道里正在升温但还没饱和的 5 个话题,每条说明现在为什么值得下手。",
"hot-topic-radar.title": "热点雷达",
"hubspot-funnel-daily.description": "每天早上看 MQL、SQL、成交漏斗变化,标出掉单高发环节",
"hubspot-funnel-daily.prompt": "每天早上 9:00 看 HubSpot 漏斗:MQL、SQL、成交各阶段的变化,对比上周标出掉单高发的环节。",
"hubspot-funnel-daily.title": "HubSpot 漏斗日报",
"industry-morning-brief.description": "每天早上把你行业 5 条重要新闻、融资、政策变化做成 5 分钟读物",
"industry-morning-brief.prompt": "每天早上 8:00 把我行业 5 条重要新闻、融资、政策变化汇总成 5 分钟读物。",
"industry-morning-brief.title": "行业早餐",
"industry-research-weekly.description": "告诉我你研究的赛道,每周一给你一份市场动态、融资、新玩家、监管变化汇总",
"industry-research-weekly.prompt": "每周一早上 9:00 汇总我赛道的市场动态、融资、新玩家、监管变化,整理成研究简报。",
"industry-research-weekly.title": "行业研究周报",
"invoice-collection-daily.description": "每天早上看哪些发票逾期了、逾期多少天、该发催款邮件了",
"invoice-collection-daily.prompt": "每天早上 10:00 列出逾期发票和对接联系人,并为每条草拟一封礼貌的催款邮件。",
"invoice-collection-daily.title": "发票催收日报",
"iteration-recap-weekly.description": "每周五下班前帮你拉本周迭代数据:完成率、逾期项、新增 Bug",
"iteration-recap-weekly.prompt": "每周五下午 17:00 复盘本周迭代:完成率、逾期项、新增 Bug,整理成下周一可直接用的复盘材料。",
"iteration-recap-weekly.title": "迭代复盘周报",
"key-account-radar.description": "告诉我核心客户的公司名,每天盯他们的新闻、融资、高管变动",
"key-account-radar.prompt": "每天早上 9:00 扫一遍我核心客户的公司新闻、融资、高管变动,挑出可作为续约谈话切入点的素材。",
"key-account-radar.title": "客户动态雷达",
"keyword-tech-feed.description": "告诉我你想追踪的技术关键词,每天带回 5 条高质量新问答 / 新博客",
"keyword-tech-feed.prompt": "每天早上 10:00 按我设定的技术关键词带回 5 条高质量的新博客或新问答。",
"keyword-tech-feed.title": "关键词技术订阅",
"kol-collab-calendar.description": "每周一同步正在合作的 KOL 进度:谁该发了、谁逾期、数据怎样",
"kol-collab-calendar.prompt": "每周一早上 9:00 同步正在进行的 KOL 合作:谁该发了、谁逾期、已发出内容的数据。",
"kol-collab-calendar.title": "KOL 合作日历",
"language-morning-bite.description": "每天给你一段 3 分钟能读完的目标语言内容 + 5 个生词卡",
"language-morning-bite.prompt": "每天早上 7:30 给我一段 3 分钟能读完的目标语言内容,加上 5 个生词卡(单词、释义、例句)。",
"language-morning-bite.title": "语言早报",
"linear-sprint-daily.description": "每天早上同步 Sprint 进度:哪些卡住了、哪些逾期、今天该做什么",
"linear-sprint-daily.prompt": "每天早上 8:30 从 Linear 拉一份 Sprint 进度:今日重点、阻塞项、昨日完成,整理成 3 条站会前可直接念的要点。",
"linear-sprint-daily.title": "Linear Sprint 日报",
"macro-economy-weekly.description": "每周一早给你汇率、利率、原油、金银、主要指数汇总",
"macro-economy-weekly.prompt": "每周一早上 8:00 给我宏观快照:汇率、利率、原油、金银、主要指数,加上一段「本周变化」总结。",
"macro-economy-weekly.title": "宏观经济周报",
"marketing-hot-radar.description": "每天追踪你行业正在发酵的 5 个营销话题:哪些值得蹭、哪些要避雷",
"marketing-hot-radar.prompt": "每天早上 10:00 追踪我行业正在发酵的 5 个营销话题,标注哪些值得蹭、哪些要避雷,各附 1-2 句理由。",
"marketing-hot-radar.title": "营销热点雷达",
"meeting-brief.description": "每天早上把今天所有会议的背景、参会人、上次纪要整理成 1 页",
"meeting-brief.prompt": "每天早上 8:30 为今天日历上的每个会议生成一页简报:背景、参会人、上次纪要,进会议室前看一眼。",
"meeting-brief.title": "会议简报",
"monetization-opportunity-weekly.description": "每周三给你内容创作者的新变现渠道和案例:广告 / 知识付费 / 会员 / 电商",
"monetization-opportunity-weekly.prompt": "每周三早上 10:00 给我我赛道相关的新变现渠道和案例:广告、知识付费、会员订阅、电商。",
"monetization-opportunity-weekly.title": "变现机会播报",
"morning-brief.description": "每天 8 点推一份:今天日程、待回邮件数、待办清单、天气",
"morning-brief.prompt": "每天早上 8:00 推送:今天日程、待回邮件数、TOP 3 待办、天气,整理成 1 分钟能读完的早报。",
"morning-brief.title": "晨间早报",
"morning-ritual.description": "每天 7 点:天气 + 今日日程 + 一条金句 + 一个动一动建议,温柔开启一天",
"morning-ritual.prompt": "每天早上 7:00 给我一份温柔的晨间仪式:天气、今日日程、一条短金句、一个轻量运动建议。如果连接了 Google Calendar,把日程锚定在那里。",
"morning-ritual.title": "晨间仪式",
"must-read-papers-weekly.description": "每周日晚帮你挑本周被引最多、讨论最热的 3 篇论文,做成精读清单",
"must-read-papers-weekly.prompt": "每周日晚 20:00 帮我挑本周我研究方向被引最多或讨论最热的 3 篇论文,整理成周末可读完的精读清单。",
"must-read-papers-weekly.title": "本周必读论文",
"newsletter-aggregator.description": "每周日晚把你订阅的 Newsletter 合并成一份摘要,周末一次性读完",
"newsletter-aggregator.prompt": "每周日晚 20:00 扫一遍我 Gmail 收件箱里本周收到的 Newsletter,按主题合并成一份周末摘要。",
"newsletter-aggregator.title": "Newsletter 聚合",
"newsletter-perf-weekly.description": "每周一帮你看 Newsletter 的打开率、点击率、取关率变化趋势,标出需要优化的环节",
"newsletter-perf-weekly.prompt": "每周一早上 10:00 回顾过去 4 周 Newsletter 的打开率、点击率、取关率,标出需要优化的人群分层。",
"newsletter-perf-weekly.title": "Newsletter 表现周报",
"onboarding-buddy-weekly.description": "新人入职 90 天内,每周一生成他的进度:任务完成、Buddy 反馈、该关注什么",
"onboarding-buddy-weekly.prompt": "每周一早上 9:00 为还在 90 天试用期内的新人生成进度卡:任务完成度、Buddy 反馈、本周该关注什么。",
"onboarding-buddy-weekly.title": "新人入职陪跑",
"oss-intel-daily.description": "每天早上给你 10 条技术栈动态:GitHub Trending、大厂新开源、关键 repo 的 release",
"oss-intel-daily.prompt": "每天早上 9:00 给我 10 条技术栈动态:GitHub Trending、大厂新开源、我关注的 repo 新 release。",
"oss-intel-daily.title": "开源情报日报",
"podcast-new-episodes.description": "告诉我你订阅的播客,每周一给你本周新集 + 值得听的 3 集推荐",
"podcast-new-episodes.prompt": "每周一早上 9:00 列出我订阅播客本周的新集,并推荐其中最值得先听的 3 集。",
"podcast-new-episodes.title": "播客新集聚合",
"portfolio-daily.description": "告诉我你的持仓股票 / 基金 / 加密货币,每天收盘后给你涨跌、重要新闻、持仓公司动态",
"portfolio-daily.prompt": "每天 16:00 收盘后给我每个持仓的当日涨跌、影响新闻和公司公告。",
"portfolio-daily.title": "持仓日报",
"prd-review-reminder.description": "每周五盘点本周该评审的 PRD 和决策项,别让文档压在草稿箱",
"prd-review-reminder.prompt": "每周五下午 15:00 盘点我 Notion 里本周该评审的 PRD 和决策文档,标出仍卡在草稿状态的。",
"prd-review-reminder.title": "PRD 评审提醒",
"pre-market-brief.description": "每天开盘前 30 分钟给你宏观要闻、重要财报、你持仓公司的动态",
"pre-market-brief.prompt": "每天早上 9:00 给我开盘前简报:宏观要闻、今日重要财报、我持仓公司的动态。",
"pre-market-brief.title": "开盘前简报",
"precious-metals-daily.description": "每天收盘后推送金银铜油主要品种的价格和日变化幅度,波动超阈值立刻标红",
"precious-metals-daily.prompt": "每天 16:00 收盘后给我金、银、铜、原油的当日价格和日变化幅度,单日波动超过 2% 立刻标红。",
"precious-metals-daily.title": "金银油价日报",
"recruit-funnel-daily.description": "每天早上看各岗位新投递、待面试、待反馈数,标出面试官拖着的人选",
"recruit-funnel-daily.prompt": "每天早上 9:00 按岗位汇总招聘漏斗:新投递、待面试、待反馈数,标出被面试官卡住的人选。",
"recruit-funnel-daily.title": "招聘漏斗日报",
"regulation-watch-weekly.description": "告诉我你关注的合规领域(数据 / 税务 / 劳动法),每周一给你一份变更摘要和影响判断",
"regulation-watch-weekly.prompt": "每周一早上 10:00 汇总我追踪的合规领域(数据 / 税务 / 劳动法)过去一周的变更,并判断对我们的影响。",
"regulation-watch-weekly.title": "法规变更追踪",
"renewal-risk-weekly.description": "每周一扫一遍本月到期合同,标出使用频次下降的高风险客户",
"renewal-risk-weekly.prompt": "每周一早上 9:00 扫一遍 HubSpot 中本月到期合同,标出使用频次下降的高风险客户,并为每条高风险账户建议挽留动作。",
"renewal-risk-weekly.title": "续费风险预警",
"repo-health-weekly.description": "每周一帮你看你维护的 repo:Issue 堆积、PR 停滞、CI 失败、依赖告警",
"repo-health-weekly.prompt": "每周一早上 9:00 检查我维护的 GitHub repoIssue 堆积、PR 停滞、CI 失败、依赖告警,挑出本周该处理的事项。",
"repo-health-weekly.title": "仓库健康周报",
"schedule.daily": "每天 {{time}}",
"schedule.weekly": "每{{weekday}} {{time}}",
"section.title": "试试这些定时任务",
"seo-weekly-report.description": "每周一一份轻量 SEO 报告:排名变化、新关键词机会、值得翻新的页面",
"seo-weekly-report.prompt": "每周一早上 9:00 给我一份轻量 SEO 周报:排名升 / 降 TOP 变动、5 个值得关注的新关键词、3 个适合内容翻新的老页面。",
"seo-weekly-report.title": "SEO 排名周报",
"series-update-weekly.description": "告诉我你在追的剧 / 小说 / 漫画,每周给你更新提醒和剧情回顾",
"series-update-weekly.prompt": "每周一早上 9:00 给我我在追的剧、小说、漫画的更新提醒和短剧情回顾。",
"series-update-weekly.title": "追更日报",
"standup-brief.description": "每天站会前 15 分钟帮你拉一份 Linear 进度简报:今日重点、阻塞项、昨日完成",
"standup-brief.prompt": "每天早上 8:30 拉一份 Linear 站会简报:今日重点、阻塞项、昨日完成,整理成 3 条站会前可直接念的要点。",
"standup-brief.title": "站会简报",
"sunday-reflection.description": "每周日晚陪你走 5 个问题:最有成就感的事、最想吐槽的事、下周 3 件重要事",
"sunday-reflection.prompt": "每周日晚 21:00 陪我走 5 个复盘问题:本周最有成就感的事、最想吐槽的事、下周 3 件重要事、本周学到的、本周应该放下的。",
"sunday-reflection.title": "周日复盘",
"team-status-weekly.description": "每周一看团队请假、加班、会议时长趋势,预警潜在倦怠信号",
"team-status-weekly.prompt": "每周一早上 9:00 回顾团队过去一周的请假、加班、会议时长趋势,预警有倦怠风险的成员。",
"team-status-weekly.title": "团队状态周报",
"tech-trend-weekly.description": "每周一帮你总结前端 / 后端 / AI 圈的重要动态:论文、框架、融资",
"tech-trend-weekly.prompt": "每周一早上 8:00 总结前端、后端、AI 圈过去一周的重要动态:论文、框架、融资,整理成 10 条 + 一句要点。",
"tech-trend-weekly.title": "技术趋势周刊",
"travel-inspiration-weekly.description": "每周三给你想去城市的机票价格变动、签证政策、最佳出行时间",
"travel-inspiration-weekly.prompt": "每周三早上 10:00 给我心愿城市的机票价格变化、签证政策、最佳出行时间。",
"travel-inspiration-weekly.title": "旅行灵感周报",
"twitter-weekly-recap.description": "每周一帮你复盘过去 7 天的推文表现:涨粉最猛的、互动最差的、为什么",
"twitter-weekly-recap.prompt": "每周一早上 10:00 复盘我 X (Twitter) 过去 7 天的推文表现:涨粉最猛的、互动最差的,并给出原因假设和下周 3 个尝试方向。",
"twitter-weekly-recap.title": "推特周报",
"user-feedback-daily.description": "每天把各渠道用户反馈(应用商店、社媒、客服)聚合成 TOP 20 条,按情绪和主题分类",
"user-feedback-daily.prompt": "每天早上 9:00 把各渠道用户反馈(应用商店、社媒、客服)聚合成 TOP 20 条,按情绪和主题分类。",
"user-feedback-daily.title": "用户反馈日报",
"user-interview-schedule.description": "每周一帮你梳理本周访谈:谁、什么时候、问题列表准备好没",
"user-interview-schedule.prompt": "每周一早上 9:00 列出本周已排期的用户访谈:访谈对象、时间、准备清单(问题列表是否齐全、录制设备是否就位)。",
"user-interview-schedule.title": "用户访谈排期",
"vercel-health-weekly.description": "每周一帮你盘点上周部署成功率、构建时长、流量异常",
"vercel-health-weekly.prompt": "每周一早上 10:00 盘点 Vercel 过去一周的部署:成功率、构建时长、流量异常,标出累积问题。",
"vercel-health-weekly.title": "Vercel 健康周报",
"viral-content-breakdown.description": "每天从你领域挑 1 条爆款帮你拆:选题、开头、结构、结尾",
"viral-content-breakdown.prompt": "每天早上 10:00 从我领域挑 1 条爆款帮我拆:选题、开头、结构、结尾,整理成可复刻的模板。",
"viral-content-breakdown.title": "爆款拆解",
"watchlist-friday.description": "每周五给你本周豆瓣 / IMDb 新上映的 5 部高分作品,附一句话短评",
"watchlist-friday.prompt": "每周五晚 18:00 从豆瓣和 IMDb 挑 5 部本周新上映的高分作品,每部附一句短评。",
"watchlist-friday.title": "观影清单",
"weekly-meeting-brief.description": "每周一早上帮你准备本周战略会的 3 个讨论要点:行业动态、内部指标、决策建议",
"weekly-meeting-brief.prompt": "每周一早上 8:30 准备本周战略会的 3 个讨论要点:行业动态、值得提的内部指标、需要决策的事项。",
"weekly-meeting-brief.title": "周会简报",
"youtube-channel-weekly.description": "每周一拉频道数据:订阅变化、热门视频、观众留存、收益变化",
"youtube-channel-weekly.prompt": "每周一早上 9:00 拉我 YouTube 频道的数据:订阅变化、热门视频、观众留存、收益变化。",
"youtube-channel-weekly.title": "YouTube 频道周报",
"youtube-weekly-recap.description": "每周一帮你拉频道过去 7 天的播放、CTR、留存曲线,标出值得拍续集的选题",
"youtube-weekly-recap.prompt": "每周一早上 9:00 拉我 YouTube 频道过去 7 天的播放、CTR、留存曲线,标出值得拍续集的选题。",
"youtube-weekly-recap.title": "YouTube 周报",
"zendesk-ticket-daily.description": "每天早上盘一下 Zendesk 工单:积压多少、SLA 逾期多少、重复问题前三名",
"zendesk-ticket-daily.prompt": "每天早上 9:00 给我 Zendesk 快照:未关单积压、SLA 逾期数量、过去 24 小时 TOP 3 重复问题。",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "令牌使用量",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "为代理执行此任务提供详细说明……",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "任务标题……",
"agentMarketplace.category.businessStrategy": "商业与战略",
"agentMarketplace.category.contentCreation": "内容创作",
"agentMarketplace.category.creatorEconomy": "创作者经济",
"agentMarketplace.category.designCreative": "设计与创意",
"agentMarketplace.category.engineering": "工程",
"agentMarketplace.category.financeLegal": "金融与法律",
"agentMarketplace.category.learningResearch": "学习与研究",
"agentMarketplace.category.marketing": "市场营销",
"agentMarketplace.category.operations": "运营",
"agentMarketplace.category.peopleHR": "人力资源",
"agentMarketplace.category.personalLife": "个人生活",
"agentMarketplace.category.productManagement": "产品管理",
"agentMarketplace.category.salesCustomer": "销售与客户",
"agentMarketplace.picker.empty": "暂无可用模板。",
"agentMarketplace.picker.failedToLoad": "加载模板失败。请稍后再试。",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} 个模板可用。",
"codeInterpreter-legacy.error": "执行出错",
"codeInterpreter-legacy.executing": "正在执行...",
"codeInterpreter-legacy.files": "文件:",
+6
View File
@@ -667,6 +667,12 @@
"tool.intervention.onboarding.agentIdentity.targetOnboarding": "目前的導引代理",
"tool.intervention.onboarding.agentIdentity.targets": "適用對象",
"tool.intervention.onboarding.agentIdentity.title": "確認代理身分更新",
"tool.intervention.onboarding.userProfile.applyHint": "這些詳細資料將在批准後儲存到您的個人檔案中。",
"tool.intervention.onboarding.userProfile.description": "批准此變更將更新您的入職檔案,以便代理可以量身定制未來的回覆。",
"tool.intervention.onboarding.userProfile.eyebrow": "入職批准",
"tool.intervention.onboarding.userProfile.fullName": "全名",
"tool.intervention.onboarding.userProfile.responseLanguage": "回應語言",
"tool.intervention.onboarding.userProfile.title": "確認您的檔案更新",
"tool.intervention.pending": "待處理",
"tool.intervention.reject": "拒絕",
"tool.intervention.rejectAndContinue": "拒絕後重新執行",
+1
View File
@@ -91,6 +91,7 @@
"response.InvalidOllamaArgs": "Ollama 配置不正確,請檢查 Ollama 配置後重試",
"response.InvalidProviderAPIKey": "{{provider}} API 金鑰不正確或為空,請檢查 {{provider}} API 金鑰後重試",
"response.InvalidVertexCredentials": "Vertex 認證未通過,請檢查認證憑證後重試",
"response.LobeHubModelDeprecated": "模型 \"{{model}}\" 已不再可用。請從模型選擇器中選擇一個當前的模型。",
"response.LocationNotSupportError": "很抱歉,你的所在位置不支持此模型服務,可能是由於地區限制或服務未開通。請確認當前位置是否支持使用此服務,或嘗試使用其他位置信息。",
"response.ModelNotFound": "很抱歉,無法請求到相應的模型,可能是模型不存在或沒有訪問權限導致,請更換 API Key 或調整訪問權限後重試",
"response.NoOpenAIAPIKey": "OpenAI API 金鑰為空,請添加自訂 OpenAI API 金鑰",
+2
View File
@@ -1,5 +1,7 @@
{
"action.connect.button": "連接 {{provider}}",
"action.connect.error": "連線失敗,請再試一次。",
"action.connect.popupBlocked": "連線彈出視窗被阻擋。請在瀏覽器中允許彈出視窗以繼續。",
"action.create.error": "建立任務失敗。請再試一次。",
"action.create.success": "已新增排程任務,可在 Lobe AI 中查看。",
"action.createButton": "新增為排程任務",
+16
View File
@@ -17,6 +17,22 @@
"agentGroupManagement.executeTask.tokens": "Token 消耗",
"agentGroupManagement.executeTasks.intervention.instructionPlaceholder": "請輸入代理執行此任務的詳細指示……",
"agentGroupManagement.executeTasks.intervention.titlePlaceholder": "任務標題……",
"agentMarketplace.category.businessStrategy": "商業與策略",
"agentMarketplace.category.contentCreation": "內容創作",
"agentMarketplace.category.creatorEconomy": "創作者經濟",
"agentMarketplace.category.designCreative": "設計與創意",
"agentMarketplace.category.engineering": "工程",
"agentMarketplace.category.financeLegal": "財務與法律",
"agentMarketplace.category.learningResearch": "學習與研究",
"agentMarketplace.category.marketing": "行銷",
"agentMarketplace.category.operations": "營運",
"agentMarketplace.category.peopleHR": "人事與人力資源",
"agentMarketplace.category.personalLife": "個人生活",
"agentMarketplace.category.productManagement": "產品管理",
"agentMarketplace.category.salesCustomer": "銷售與客戶",
"agentMarketplace.picker.empty": "沒有可用的範本。",
"agentMarketplace.picker.failedToLoad": "範本載入失敗。請稍後再試。",
"agentMarketplace.picker.summary": "{{filtered}} / {{total}} 個範本可用。",
"codeInterpreter-legacy.error": "執行錯誤",
"codeInterpreter-legacy.executing": "執行中...",
"codeInterpreter-legacy.files": "檔案:",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@lobehub/lobehub",
"version": "2.1.53",
"version": "2.1.55",
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
"keywords": [
"framework",
@@ -113,7 +113,7 @@ class SimpleAgent implements Agent {
// Agent decision logic - based on execution phase and context
async runner(context: AgentRuntimeContext, state: AgentState) {
console.log(`[${context.phase}] 对话状态: ${this.conversationState}`);
console.log(`[${context.phase}] Conversation state: ${this.conversationState}`);
switch (context.phase) {
case 'init': {
@@ -125,7 +125,7 @@ class SimpleAgent implements Agent {
case 'user_input': {
// User input phase
const userPayload = context.payload as { isFirstMessage: boolean; message: any };
console.log(`👤 用户消息: ${userPayload.message.content}`);
console.log(`👤 User message: ${userPayload.message.content}`);
// Only process when in waiting_user state
if (this.conversationState === 'waiting_user') {
@@ -140,7 +140,7 @@ class SimpleAgent implements Agent {
}
// Do not process user input in other states, end conversation
console.log(`⚠️ 忽略用户输入,当前状态: ${this.conversationState}`);
console.log(`⚠️ Ignoring user input, current state: ${this.conversationState}`);
return {
reason: `Not in waiting_user state: ${this.conversationState}`,
type: 'finish' as const,
@@ -164,7 +164,7 @@ class SimpleAgent implements Agent {
this.conversationState = 'executing_tools';
console.log(
'🔧 需要执行工具:',
'🔧 Tools to execute:',
toolCalls.map((call: any) => call.function.name),
);
@@ -187,7 +187,7 @@ class SimpleAgent implements Agent {
case 'tool_result': {
// Tool execution result phase
const toolPayload = context.payload as { result: any; toolMessage: any };
console.log(`🛠️ 工具执行完成: ${JSON.stringify(toolPayload.result)}`);
console.log(`🛠️ Tool execution completed: ${JSON.stringify(toolPayload.result)}`);
// Remove the executed tool
this.pendingToolCalls = this.pendingToolCalls.slice(1);
@@ -219,7 +219,7 @@ class SimpleAgent implements Agent {
case 'error': {
// Error phase
const errorPayload = context.payload as { error: any };
console.error('❌ 错误状态:', errorPayload.error);
console.error('❌ Error state:', errorPayload.error);
return { reason: 'Error occurred', type: 'finish' as const };
}
@@ -232,10 +232,10 @@ class SimpleAgent implements Agent {
// Main function
async function main() {
console.log('🚀 简单的 OpenAI Tools Agent 示例\n');
console.log('🚀 Simple OpenAI Tools Agent Example\n');
if (!process.env.OPENAI_API_KEY) {
console.error('❌ 请设置 OPENAI_API_KEY 环境变量');
console.error('❌ Please set the OPENAI_API_KEY environment variable');
return;
}
@@ -245,7 +245,7 @@ async function main() {
// Test message
const testMessage = process.argv[2] || 'What time is it? Also calculate 15 * 8 + 7';
console.log(`💬 用户: ${testMessage}\n`);
console.log(`💬 User: ${testMessage}\n`);
// Create initial state
let state = AgentRuntime.createInitialState({
@@ -273,21 +273,21 @@ async function main() {
}
case 'llm_result': {
if ((event as any).result.tool_calls) {
console.log('\n\n🔧 需要调用工具...');
console.log('\n\n🔧 Calling tools...');
}
break;
}
case 'tool_result': {
console.log(`\n🛠️ 工具执行结果:`, event.result);
console.log(`\n🛠️ Tool execution result:`, event.result);
console.log('\n🤖 AI: ');
break;
}
case 'done': {
console.log('\n\n✅ 对话完成');
console.log('\n\n✅ Conversation complete');
break;
}
case 'error': {
console.error('\n❌ 错误:', event.error);
console.error('\n❌ Error:', event.error);
break;
}
}
@@ -297,7 +297,7 @@ async function main() {
nextContext = result.nextContext; // use the returned nextContext
}
console.log(`\n📊 总共执行了 ${state.stepCount} 个步骤`);
console.log(`\n📊 Total steps executed: ${state.stepCount}`);
}
main().catch(console.error);
@@ -14,6 +14,8 @@ export const AGENT_SIGNAL_SOURCE_TYPES = {
clientRuntimeStart: 'client.runtime.start',
runtimeAfterStep: 'runtime.after_step',
runtimeBeforeStep: 'runtime.before_step',
toolOutcomeCompleted: 'tool.outcome.completed',
toolOutcomeFailed: 'tool.outcome.failed',
} as const;
type ValueOf<TValue> = TValue[keyof TValue];
@@ -43,7 +45,7 @@ export interface AgentSignalSourcePayloadMap {
[AGENT_SIGNAL_SOURCE_TYPES.agentUserMessage]: {
agentId?: string;
documentPayload?: Record<string, unknown>;
intents?: Array<'document' | 'memory' | 'persona' | 'prompt'>;
intents?: Array<'document' | 'memory' | 'persona' | 'prompt' | 'skill'>;
memoryPayload?: Record<string, unknown>;
message: string;
messageId: string;
@@ -121,6 +123,41 @@ export interface AgentSignalSourcePayloadMap {
topicId?: string;
turnCount?: number;
};
[AGENT_SIGNAL_SOURCE_TYPES.toolOutcomeCompleted]: {
agentId?: string;
domainKey?: string;
intentClass?: string;
messageId?: string;
operationId?: string;
outcome: {
action?: string;
status: 'skipped' | 'succeeded';
summary?: string;
};
relatedObjects?: Array<{ objectId: string; objectType: string; relation?: string }>;
taskId?: string;
tool: { apiName?: string; identifier: string };
toolCallId?: string;
topicId?: string;
};
[AGENT_SIGNAL_SOURCE_TYPES.toolOutcomeFailed]: {
agentId?: string;
domainKey?: string;
intentClass?: string;
messageId?: string;
operationId?: string;
outcome: {
action?: string;
errorReason?: string;
status: 'failed';
summary?: string;
};
relatedObjects?: Array<{ objectId: string; objectType: string; relation?: string }>;
taskId?: string;
tool: { apiName?: string; identifier: string };
toolCallId?: string;
topicId?: string;
};
}
/** AgentSignal source variant with source-type-specific payload typing. */
@@ -174,6 +211,12 @@ export type SourceClientRuntimeStart = AgentSignalSourceVariant<'client.runtime.
/** Client runtime-complete source variant. */
export type SourceClientRuntimeComplete = AgentSignalSourceVariant<'client.runtime.complete'>;
/** Tool outcome-completed source variant. */
export type SourceToolOutcomeCompleted = AgentSignalSourceVariant<'tool.outcome.completed'>;
/** Tool outcome-failed source variant. */
export type SourceToolOutcomeFailed = AgentSignalSourceVariant<'tool.outcome.failed'>;
/** Source types accepted by browser producers through the authenticated edge. */
export const AGENT_SIGNAL_CLIENT_SOURCE_TYPES = [
AGENT_SIGNAL_SOURCE_TYPES.clientGatewayError,
@@ -83,9 +83,16 @@ export const systemPrompt = `You have access to a Tools Activator that allows yo
- Never ask users to paste API keys directly in chat always use \`lobe-creds\` to store them securely
- \`lobe-creds\` works together with \`lobe-cloud-sandbox\` for secure credential injection
**Credential Injection Locations:**
**Credential Usage by Runtime:**
In cloud sandbox (\`injectCredsToSandbox\` available):
- Environment-based credentials (oauth, kv-env, kv-header) \`~/.creds/env\` — use \`runCommand\` with \`bash -c "source ~/.creds/env && your_command"\`
- File-based credentials \`~/.creds/files/{key}/{filename}\` — use file path directly in your code
On desktop/local (no sandbox, \`injectCredsToSandbox\` NOT available):
- Use \`getPlaintextCred\` to retrieve values, then pass as inline env vars in \`runCommand\`
- Example: \`runCommand({ command: "GITHUB_TOKEN='xxx' gh repo list" })\`
- File credentials: use \`getPlaintextCred\` to get the file path from the response state
</credentials_management>
<best_practices>
@@ -379,6 +379,32 @@ export class CredsExecutionRuntime {
};
}
// Secure input mode: fields provided without values — requires web UI
if ((!args.values || Object.keys(args.values).length === 0) && args.fields?.length) {
return {
content:
'Secure credential input is only available in the web UI. In background execution, credentials must be provided with values directly.',
state: {
key: args.key,
message: 'Secure input requires web UI',
success: false,
},
success: true,
};
}
if (!args.values || Object.keys(args.values).length === 0) {
return {
content:
'Failed to save credential: values must be provided as key-value pairs (e.g., { "API_KEY": "sk-xxx" }).',
error: {
message: 'values is empty or missing',
type: 'InvalidParams',
},
success: false,
};
}
await this.credsService.saveKVCred({
description: args.description,
key: args.key,
@@ -0,0 +1,138 @@
'use client';
import type { BuiltinInterventionProps } from '@lobechat/types';
import { Button, Flexbox, Text } from '@lobehub/ui';
import { Input, Tag } from 'antd';
import { memo, useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { lambdaClient } from '@/libs/trpc/client';
import type { SaveCredsParams } from '../../../types';
import { styles } from './style';
const SecureCredentialForm = memo<BuiltinInterventionProps<SaveCredsParams>>(
({ args, interactionMode, onInteractionAction }) => {
const { t } = useTranslation('ui');
const isCustom = interactionMode === 'custom';
const { key, name, type, fields = [], description } = args;
const [values, setValues] = useState<Record<string, string>>(() => {
const init: Record<string, string> = {};
for (const field of fields) {
init[field.name] = '';
}
return init;
});
const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState<string>();
const allFilled = fields.every((f) => values[f.name]?.trim());
const handleSave = useCallback(async () => {
if (!onInteractionAction || !allFilled) return;
setSubmitting(true);
setError(undefined);
try {
// Save credential directly via tRPC — values never enter AI context
await lambdaClient.market.creds.createKV.mutate({
description,
key,
name,
type: type as 'kv-env' | 'kv-header',
values,
});
// Notify the tool chain with success metadata only (no secret values)
await onInteractionAction({
payload: { key, name, success: true },
type: 'submit',
});
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to save credential');
setSubmitting(false);
}
}, [allFilled, description, key, name, onInteractionAction, type, values]);
const handleSkip = useCallback(async () => {
if (!onInteractionAction) return;
await onInteractionAction({
reason: 'User cancelled secure credential input',
type: 'skip',
});
}, [onInteractionAction]);
// Non-custom mode: show summary only (standard approve/reject buttons handle it)
if (!isCustom) {
return (
<Flexbox gap={8}>
<Text>
{t('common.save', { defaultValue: 'Save' })}: {name}
</Text>
<Text style={{ fontSize: 13 }} type="secondary">
{t('common.type', { defaultValue: 'Type' })}: {type} | Key: {key}
</Text>
{fields.length > 0 && (
<Text style={{ fontSize: 12 }} type="secondary">
{fields.map((f) => f.label || f.name).join(', ')}
</Text>
)}
</Flexbox>
);
}
return (
<div className={styles.root}>
<div className={styles.header}>
<Text style={{ fontWeight: 500 }}>🔐 {name}</Text>
{description && (
<Text style={{ fontSize: 13 }} type="secondary">
{description}
</Text>
)}
<Flexbox horizontal gap={4}>
<Tag className={styles.tag}>{key}</Tag>
<Tag className={styles.tag}>{type}</Tag>
</Flexbox>
</div>
<Flexbox gap={8}>
{fields.map((field) => (
<Flexbox gap={4} key={field.name}>
<span className={styles.fieldLabel}>{field.label || field.name}</span>
<Input.Password
autoComplete="off"
placeholder={field.name}
status={error ? 'error' : undefined}
value={values[field.name]}
onChange={(e) => setValues((prev) => ({ ...prev, [field.name]: e.target.value }))}
onPressEnter={() => {
if (allFilled) handleSave();
}}
/>
</Flexbox>
))}
</Flexbox>
{error && (
<Text style={{ fontSize: 12 }} type="danger">
{error}
</Text>
)}
<div className={styles.footer}>
<Button onClick={handleSkip}>{t('form.skip', { defaultValue: 'Skip' })}</Button>
<Button disabled={!allFilled} loading={submitting} type="primary" onClick={handleSave}>
{t('common.save', { defaultValue: 'Save' })}
</Button>
</div>
</div>
);
},
);
SecureCredentialForm.displayName = 'SecureCredentialForm';
export default SecureCredentialForm;
@@ -0,0 +1,29 @@
import { createStaticStyles } from 'antd-style';
export const styles = createStaticStyles(({ css, cssVar }) => ({
fieldLabel: css`
font-size: 13px;
font-weight: 500;
color: ${cssVar.colorText};
`,
footer: css`
display: flex;
gap: 8px;
justify-content: flex-end;
padding-block-start: 4px;
`,
header: css`
display: flex;
flex-direction: column;
gap: 4px;
`,
root: css`
display: flex;
flex-direction: column;
gap: 12px;
`,
tag: css`
font-family: ${cssVar.fontFamilyCode};
font-size: 12px;
`,
}));
@@ -0,0 +1,8 @@
import type { BuiltinIntervention } from '@lobechat/types';
import { CredsApiName } from '../../types';
import SecureCredentialForm from './SecureCredentialForm';
export const CredsInterventions: Record<string, BuiltinIntervention> = {
[CredsApiName.saveCreds]: SecureCredentialForm as BuiltinIntervention,
};
@@ -1,4 +1,3 @@
// Client-side components for Creds tool
// Placeholder for future Render/Streaming components
export {};
export { CredsManifest } from '../manifest';
export * from '../types';
export { CredsInterventions } from './Intervention';
@@ -0,0 +1,24 @@
import type { DynamicInterventionResolver } from '@lobechat/types';
/**
* Dynamic intervention resolver for saveCreds secure input mode.
* Returns true (intervention needed) when `values` is missing/empty
* and `fields` is provided indicating the user wants secure input.
*/
export const credsSecureInputAudit: DynamicInterventionResolver = async (toolArgs) => {
const values = toolArgs.values;
const fields = toolArgs.fields;
// Secure input mode: fields provided but no values
if (
fields &&
Array.isArray(fields) &&
fields.length > 0 &&
(!values || (typeof values === 'object' && Object.keys(values).length === 0))
) {
return true;
}
// Direct save mode: values provided, no intervention needed
return false;
};
@@ -592,7 +592,7 @@ class CredsExecutor extends BaseExecutor<typeof CredsApiName> {
const raw = params as any;
const name: string = params.name || raw.displayName || params.key;
let values: Record<string, string> = params.values;
let values: Record<string, string> | undefined = params.values;
if (!values && typeof raw.value === 'string') {
values = {};
for (const line of (raw.value as string).split('\n')) {
@@ -603,6 +603,22 @@ class CredsExecutor extends BaseExecutor<typeof CredsApiName> {
}
}
// Secure input mode: fields provided without values — the intervention component
// handles saving directly via tRPC, so the executor should not run.
// This branch handles edge cases (e.g., server-side execution).
if ((!values || Object.keys(values).length === 0) && raw.fields?.length > 0) {
return {
content:
'Secure credential input is only available in the web UI. Please use the LobeHub web interface to save credentials securely.',
state: {
key: params.key,
message: 'Secure input requires web UI',
success: false,
},
success: true,
};
}
if (!values || Object.keys(values).length === 0) {
return {
content:
+2
View File
@@ -1,3 +1,4 @@
export { credsSecureInputAudit } from './credsSecureInputAudit';
export { CredsExecutionRuntime, type ICredsService } from './ExecutionRuntime';
export {
checkCredsSatisfied,
@@ -23,6 +24,7 @@ export {
type InitiateOAuthConnectParams,
type InjectCredsToSandboxParams,
type InjectCredsToSandboxState,
type SaveCredsField,
type SaveCredsParams,
type SaveCredsState,
} from './types';
+33 -5
View File
@@ -45,7 +45,7 @@ export const CredsManifest: BuiltinToolManifest = {
},
{
description:
'Retrieve the plaintext value of a stored credential by its key. Use this when you need to access a credential for making API calls or other operations. Only call this when you actually need the credential value.',
'Retrieve the plaintext value of a stored credential by its key. Use this when you need to access a credential for making API calls or other operations. Only call this when you actually need the credential value. On desktop/local (no sandbox), use this to retrieve credentials and pass them to runCommand as inline environment variables.',
name: CredsApiName.getPlaintextCred,
parameters: {
additionalProperties: false,
@@ -65,7 +65,7 @@ export const CredsManifest: BuiltinToolManifest = {
},
{
description:
'Inject credentials into the sandbox environment as environment variables. Only available when sandbox mode is enabled. Use this before running code that requires credentials.',
'Inject credentials into the sandbox environment as environment variables. Only available when sandbox mode is enabled — do NOT call this on desktop/local. Use this before running code that requires credentials. For desktop/local, use getPlaintextCred instead.',
name: CredsApiName.injectCredsToSandbox,
parameters: {
additionalProperties: false,
@@ -84,7 +84,14 @@ export const CredsManifest: BuiltinToolManifest = {
},
{
description:
'Save a new credential securely. Use this when the user wants to store sensitive information like API keys, tokens, or secrets. The credential will be encrypted and stored securely.',
'Save a new credential securely. Use this when the user wants to store sensitive information like API keys, tokens, or secrets. The credential will be encrypted and stored securely. When the user chooses secure input mode, omit `values` and provide `fields` instead — a secure form will appear for the user to fill in the values directly without exposing them to the AI context.',
humanIntervention: {
dynamic: {
default: 'never',
policy: 'always',
type: 'credsSecureInput',
},
},
name: CredsApiName.saveCreds,
parameters: {
additionalProperties: false,
@@ -93,6 +100,27 @@ export const CredsManifest: BuiltinToolManifest = {
description: 'Optional description explaining what this credential is used for',
type: 'string',
},
fields: {
description:
'Field definitions for secure input mode. Provide this WITHOUT values to trigger a secure form where the user fills in credential values directly. Each field defines an environment variable or header key that the user will provide.',
items: {
additionalProperties: false,
properties: {
label: {
description: 'Display label for the field (defaults to name if omitted)',
type: 'string',
},
name: {
description:
'Environment variable or header name (e.g., "GITHUB_TOKEN", "OPENAI_API_KEY")',
type: 'string',
},
},
required: ['name'],
type: 'object',
},
type: 'array',
},
key: {
description:
'Unique identifier key for the credential (e.g., "openai", "github-token"). Use lowercase with hyphens.',
@@ -113,11 +141,11 @@ export const CredsManifest: BuiltinToolManifest = {
type: 'string',
},
description:
'Key-value pairs of the credential. For kv-env, the key should be the environment variable name (e.g., {"OPENAI_API_KEY": "sk-..."})',
'Key-value pairs of the credential. For kv-env, the key should be the environment variable name (e.g., {"OPENAI_API_KEY": "sk-..."}). Omit this when using secure input mode (provide `fields` instead).',
type: 'object',
},
},
required: ['key', 'name', 'type', 'values'],
required: ['key', 'name', 'type'],
type: 'object',
} satisfies JSONSchema7,
},
+64 -1
View File
@@ -21,7 +21,7 @@ Sandbox mode: {{sandbox_enabled}}
1. **Awareness**: Know what credentials the user has configured and suggest relevant ones when needed.
2. **Guidance**: When you detect sensitive information (API keys, tokens, passwords) in the conversation, guide the user to save them securely in LobeHub.
3. **Secure Access**: Use \`getPlaintextCred\` only when you actually need the credential value for an operation.
4. **Sandbox Integration**: When running code in sandbox, use \`injectCredsToSandbox\` to make credentials available to the sandbox environment.
4. **Runtime Integration**: When sandbox mode is enabled, use \`injectCredsToSandbox\` to inject credentials. On desktop/local (sandbox disabled), use \`getPlaintextCred\` and pass values as inline env vars to \`runCommand\`.
</core_responsibilities>
<tooling>
@@ -53,6 +53,31 @@ When a user mentions they want to use one of these services, use \`initiateOAuth
- **Explain the benefit**: Let users know that saved credentials are encrypted and can be easily reused across conversations.
</security_guidelines>
<secure_input_mode>
**Secure Save Flow** when the user wants to save credentials without exposing values in chat history:
1. **User provides values directly** in the conversation (e.g., "save my key sk-xxx"):
- Call \`saveCreds\` with \`values\` directly — do NOT trigger secure input.
- After saving, remind the user: "Your credential has been saved. Note that the value appeared in the chat history — you may want to edit or delete the message above to remove the plaintext."
2. **User has NOT provided values yet** and wants to add a credential:
- Ask whether they want to:
a) Paste the value in chat (faster)
b) Use **secure input** (values won't appear in chat history)
3. **User chooses secure input**:
- Call \`saveCreds\` with metadata and \`fields\` only — omit \`values\`.
- Example: \`saveCreds({ key: "github", name: "GitHub Token", type: "kv-env", fields: [{ name: "GITHUB_TOKEN", label: "GitHub Token" }] })\`
- A secure form will appear for the user to fill in credential values directly.
- You will receive a confirmation after the user saves successfully.
4. **User says "secure save" but also provides plaintext** in their message:
- Save using \`saveCreds\` with \`values\` (since the values are already in chat context).
- After saving, remind the user to edit or delete the message containing the plaintext value.
**Important**: The \`fields\` parameter defines what the user will see in the secure form. Each field should have a \`name\` (the env var or header key) and optionally a \`label\` (human-readable display text).
</secure_input_mode>
<credential_saving_triggers>
Proactively suggest saving credentials when you detect:
- API keys (e.g., "sk-...", "api_...", patterns like "OPENAI_API_KEY=...")
@@ -69,6 +94,8 @@ When suggesting to save, always:
</credential_saving_triggers>
<sandbox_integration>
**Only applies when sandbox mode is enabled (current value: {{sandbox_enabled}}).**
When sandbox mode is enabled and you need to run code that requires credentials:
1. Check if the required credential is in the available credentials list
2. Use \`injectCredsToSandbox\` to inject the credential before running code
@@ -93,6 +120,42 @@ When sandbox mode is enabled and you need to run code that requires credentials:
- Use the file path directly in your code (e.g., \`GOOGLE_APPLICATION_CREDENTIALS=~/.creds/files/gcp-service-account/credentials.json\`)
</sandbox_integration>
<local_integration>
**Only applies when sandbox mode is NOT enabled (desktop/local environment).**
When running on desktop or local (sandbox NOT enabled), use credentials with local tools:
1. Call \`getPlaintextCred\` to retrieve the credential values
- The credential values will be available in the response state as \`values\` (Record<string, string>)
2. Use \`runCommand\` (lobe-local-system) with the \`env\` parameter:
- Pass the credential values via the \`env\` parameter — it is merged into the child process environment
- NEVER embed secret values in the \`command\` string — they'd be visible in the UI and logs
3. Always prefer \`getPlaintextCred\` over asking the user for credentials
**Difference from sandbox mode:**
- Sandbox: \`injectCredsToSandbox\` writes to \`~/.creds/env\`, then \`source ~/.creds/env && cmd\`
- Local: \`getPlaintextCred\` returns values in state → pass via \`runCommand\`'s \`env\` parameter
**Example for local execution:**
\`\`\`
// 1. Get credential first
const cred = getPlaintextCred({ key: "github" })
// cred.state.values = { GITHUB_TOKEN: "ghp_xxx" }
// 2. Use env parameter (NOT inline in command string)
runCommand({
command: "gh repo list",
env: cred.state.values,
description: "List repos"
})
\`\`\`
**Important:**
- Never pass credential values in the \`command\` string — use the \`env\` parameter of \`runCommand\` instead
- Never pass credential values to \`executeCode\` — it runs in an isolated process without env support
- File credentials: \`getPlaintextCred\` returns a \`fileUrl\` (download URL) in state — use \`runCommand\` with \`curl\` or \`writeLocalFile\` to save the file locally first, then reference the local path
</local_integration>
<klavis_integrations>
{{KLAVIS_SERVICES_LIST}}
</klavis_integrations>
+20 -2
View File
@@ -106,11 +106,28 @@ export interface InjectCredsToSandboxState {
success: boolean;
}
export interface SaveCredsField {
/**
* Display label for this field
*/
label?: string;
/**
* Environment variable or header name (e.g., "GITHUB_TOKEN")
*/
name: string;
}
export interface SaveCredsParams {
/**
* Optional description for the credential
*/
description?: string;
/**
* Field definitions for secure input mode.
* When provided without values, triggers the secure credential form
* where the user fills in values directly without exposing them to AI context.
*/
fields?: SaveCredsField[];
/**
* Unique key for the credential (used for reference)
*/
@@ -124,9 +141,10 @@ export interface SaveCredsParams {
*/
type: CredType;
/**
* Key-value pairs of the credential (for kv-env and kv-header types)
* Key-value pairs of the credential (for kv-env and kv-header types).
* Optional in secure input mode user fills values via the secure form instead.
*/
values: Record<string, string>;
values?: Record<string, string>;
}
export interface SaveCredsState {
@@ -298,6 +298,12 @@ export const LocalSystemManifest: BuiltinToolManifest = {
'Clear description of what this command does (5-10 words, in active voice). Use the same language as the user input.',
type: 'string',
},
env: {
additionalProperties: { type: 'string' },
description:
'Optional environment variables to set for this command. Use this for securely passing credentials (e.g., API tokens) — do NOT embed secrets in the command string. Values are merged into the child process environment.',
type: 'object',
},
run_in_background: {
description: 'Set to true to run command in background and return shell_id',
type: 'boolean',
@@ -20,6 +20,14 @@ Memory effort level: {{memory_effort}}
4. Enforce that all memory candidates are self-contained, language-consistent, and ready for long-term reuse without relying on the surrounding conversation.
</core_responsibilities>
<routing_boundaries>
- Do **not** use memory tools for requests to create, update, refine, merge, consolidate, or store reusable skills, procedures, workflows, playbooks, checklists, agent capabilities, agent prompts, or agent documents.
- If the user asks for a "reusable skill", "future workflow", "PR review checklist skill", "agent capability", or similar operational artifact, leave it to the skill/document management path. Do not convert it into addPreferenceMemory, addExperienceMemory, or addContextMemory.
- The same boundary applies in Chinese. Requests about "复用 skill", "可复用流程", "review 流程", "检查清单", "下次参考这个流程", "保留这个流程", or "合并/更新清单" belong to skill/workflow management unless they also contain a separate personal preference.
- Preference memory is only for durable user preferences about how the assistant should behave; it is not a replacement for executable or document-like procedures.
- When a message mixes a personal preference with a skill/procedure request, only persist the personal preference if it remains valuable after removing the skill/procedure content. Otherwise skip memory.
</routing_boundaries>
<tooling>
- **queryTaxonomyOptions**: discover categories, tags, labels, statuses, roles, and relationships that already exist in memory.
- **searchUserMemory**: queries?, categories?, tags?, labels?, layers?, types?, relationships?, status?, timeIntent?, timeRange?, topK? Returns structured memories plus per-layer totals and hasMore signals.
@@ -73,6 +81,8 @@ Query construction guidance:
- Include concrete actors, locations, dates, motivations, emotions, and outcomes.
- Reference retrieved memories to decide if information is new, materially refined, or a status/progress update. Skip items that add no meaningful nuance.
- Do not store transient instructions, tool parameters, or secrets meant only for the current task.
- Do not summarize skill-management requests as user preferences. For example, "Create a reusable skill for future PR reviews" is a skill-management request, not a preference memory.
- Do not summarize Chinese workflow retention requests as memories. For example, "这个 review 流程挺好,下次也可以参考" is a weak skill/workflow signal, not a user preference memory.
</formatting_guardrails>
<layer_specific_highlights>
@@ -1,6 +1,8 @@
import { credsSecureInputAudit } from '@lobechat/builtin-tool-creds';
import { pathScopeAudit } from '@lobechat/builtin-tool-local-system';
import { type DynamicInterventionResolver } from '@lobechat/types';
export const dynamicInterventionAudits: Record<string, DynamicInterventionResolver> = {
credsSecureInput: credsSecureInputAudit,
pathScopeAudit,
};
@@ -8,6 +8,7 @@ import {
} from '@lobechat/builtin-tool-agent-marketplace/client';
import { CloudSandboxManifest } from '@lobechat/builtin-tool-cloud-sandbox';
import { CloudSandboxInterventions } from '@lobechat/builtin-tool-cloud-sandbox/client';
import { CredsInterventions, CredsManifest } from '@lobechat/builtin-tool-creds/client';
import {
GroupManagementInterventions,
GroupManagementManifest,
@@ -40,6 +41,7 @@ export const BuiltinToolInterventions: Record<string, Record<string, any>> = {
[AgentBuilderManifest.identifier]: AgentBuilderInterventions,
[AgentMarketplaceManifest.identifier]: AgentMarketplaceInterventions,
[CloudSandboxManifest.identifier]: CloudSandboxInterventions,
[CredsManifest.identifier]: CredsInterventions,
[GroupManagementManifest.identifier]: GroupManagementInterventions,
[GTDManifest.identifier]: GTDInterventions,
[LocalSystemIdentifier]: LocalSystemInterventions,
@@ -175,7 +175,7 @@ describe('MessagesEngine', () => {
{
function: {
arguments: '{"path":"/tmp/a.ts"}',
name: 'lobe-local-system____readLocalFile____builtin',
name: 'lobe-local-system____readLocalFile',
},
id: 'call_local-system-snapshot-1',
type: 'function',
@@ -184,7 +184,7 @@ describe('MessagesEngine', () => {
});
expect(result.messages).toContainEqual({
content: 'File: /tmp/a.ts (lines 0-200)\n\nconst a = 1;\n',
name: 'lobe-local-system____readLocalFile____builtin',
name: 'lobe-local-system____readLocalFile',
role: 'tool',
tool_call_id: 'call_local-system-snapshot-1',
});
@@ -44,7 +44,12 @@ describe('BriefModel', () => {
const brief = await model.create({
actions: [{ label: 'Approve', type: 'approve' }],
agentId: 'agent-1',
artifacts: ['doc-1', 'doc-2'],
artifacts: {
documents: [
{ id: 'doc-1', kind: null, title: null },
{ id: 'doc-2', kind: null, title: null },
],
},
priority: 'urgent',
summary: 'Chapter too long, suggest splitting',
taskId: null,
@@ -56,7 +61,12 @@ describe('BriefModel', () => {
expect(brief.priority).toBe('urgent');
expect(brief.agentId).toBe('agent-1');
expect(brief.actions).toEqual([{ label: 'Approve', type: 'approve' }]);
expect(brief.artifacts).toEqual(['doc-1', 'doc-2']);
expect(brief.artifacts).toEqual({
documents: [
{ id: 'doc-1', kind: null, title: null },
{ id: 'doc-2', kind: null, title: null },
],
});
});
});
@@ -625,6 +625,51 @@ describe('TaskModel', () => {
const pinned = await model.getPinnedDocuments(task.id);
expect(pinned).toHaveLength(1);
});
it('getDocumentsPinnedSince filters by createdAt and joins title/kind', async () => {
const model = new TaskModel(serverDB, userId);
const task = await model.create({ instruction: 'Test' });
const [oldDoc] = await serverDB
.insert(documents)
.values({
content: '',
fileType: 'text/plain',
source: 'test',
sourceType: 'file',
title: 'Old',
totalCharCount: 0,
totalLineCount: 0,
userId,
})
.returning();
const [newDoc] = await serverDB
.insert(documents)
.values({
content: '',
fileType: 'text/markdown',
source: 'test',
sourceType: 'file',
title: 'New',
totalCharCount: 0,
totalLineCount: 0,
userId,
})
.returning();
await model.pinDocument(task.id, oldDoc.id);
const cutoff = new Date(Date.now() + 100); // pin newDoc after this point
await new Promise((resolve) => setTimeout(resolve, 150));
await model.pinDocument(task.id, newDoc.id);
const pinnedSince = await model.getDocumentsPinnedSince(task.id, cutoff);
expect(pinnedSince).toHaveLength(1);
expect(pinnedSince[0]).toEqual({
id: newDoc.id,
kind: 'text/markdown',
title: 'New',
});
});
});
describe('checkpoint', () => {

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