@pencil-agent/nano-pencil 1.10.6 → 1.10.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/mcp/mcp-guidance.js +44 -44
- package/dist/core/model-registry.d.ts +2 -2
- package/dist/core/model-registry.js +5 -2
- package/dist/core/usage-tracker.d.ts +39 -0
- package/dist/core/usage-tracker.js +168 -0
- package/dist/extensions/agent-reach/index.d.ts +10 -0
- package/dist/extensions/agent-reach/index.js +216 -0
- package/dist/extensions/link-world/index.d.ts +1 -0
- package/dist/extensions/link-world/index.js +33 -1
- package/dist/main.js +9 -2
- package/dist/modes/interactive/components/footer.js +5 -5
- package/dist/modes/interactive/interactive-mode.js +10 -6
- package/dist/modes/interactive/theme/warm.json +81 -81
- package/dist/nanopencil-defaults.d.ts +105 -6
- package/dist/nanopencil-defaults.js +259 -15
- package/dist/packages/agent-core/agent-loop.d.ts +21 -0
- package/dist/packages/agent-core/agent-loop.js +308 -0
- package/dist/packages/agent-core/agent.d.ts +157 -0
- package/dist/packages/agent-core/agent.js +410 -0
- package/dist/packages/agent-core/index.d.ts +5 -0
- package/dist/packages/agent-core/index.js +9 -0
- package/dist/packages/agent-core/package.json +10 -0
- package/dist/packages/agent-core/proxy.d.ts +85 -0
- package/dist/packages/agent-core/proxy.js +268 -0
- package/dist/packages/agent-core/types.d.ts +178 -0
- package/dist/packages/agent-core/types.js +2 -0
- package/dist/packages/ai/api-registry.d.ts +20 -0
- package/dist/packages/ai/api-registry.js +44 -0
- package/dist/packages/ai/cli.d.ts +3 -0
- package/dist/packages/ai/cli.js +116 -0
- package/dist/packages/ai/env-api-keys.d.ts +9 -0
- package/dist/packages/ai/env-api-keys.js +100 -0
- package/dist/packages/ai/index.d.ts +22 -0
- package/dist/packages/ai/index.js +21 -0
- package/dist/packages/ai/models.d.ts +24 -0
- package/dist/packages/ai/models.generated.d.ts +13288 -0
- package/dist/packages/ai/models.generated.js +13094 -0
- package/dist/packages/ai/models.js +55 -0
- package/dist/packages/ai/package.json +10 -0
- package/dist/packages/ai/providers/amazon-bedrock.d.ts +15 -0
- package/dist/packages/ai/providers/amazon-bedrock.js +597 -0
- package/dist/packages/ai/providers/anthropic.d.ts +33 -0
- package/dist/packages/ai/providers/anthropic.js +729 -0
- package/dist/packages/ai/providers/azure-openai-responses.d.ts +15 -0
- package/dist/packages/ai/providers/azure-openai-responses.js +184 -0
- package/dist/packages/ai/providers/github-copilot-headers.d.ts +8 -0
- package/dist/packages/ai/providers/github-copilot-headers.js +29 -0
- package/dist/packages/ai/providers/google-gemini-cli.d.ts +74 -0
- package/dist/packages/ai/providers/google-gemini-cli.js +744 -0
- package/dist/packages/ai/providers/google-shared.d.ts +65 -0
- package/dist/packages/ai/providers/google-shared.js +306 -0
- package/dist/packages/ai/providers/google-vertex.d.ts +15 -0
- package/dist/packages/ai/providers/google-vertex.js +371 -0
- package/dist/packages/ai/providers/google.d.ts +13 -0
- package/dist/packages/ai/providers/google.js +352 -0
- package/dist/packages/ai/providers/openai-codex-responses.d.ts +9 -0
- package/dist/packages/ai/providers/openai-codex-responses.js +699 -0
- package/dist/packages/ai/providers/openai-completions.d.ts +15 -0
- package/dist/packages/ai/providers/openai-completions.js +727 -0
- package/dist/packages/ai/providers/openai-responses-shared.d.ts +17 -0
- package/dist/packages/ai/providers/openai-responses-shared.js +427 -0
- package/dist/packages/ai/providers/openai-responses.d.ts +13 -0
- package/dist/packages/ai/providers/openai-responses.js +198 -0
- package/dist/packages/ai/providers/register-builtins.d.ts +3 -0
- package/dist/packages/ai/providers/register-builtins.js +63 -0
- package/dist/packages/ai/providers/simple-options.d.ts +8 -0
- package/dist/packages/ai/providers/simple-options.js +35 -0
- package/dist/packages/ai/providers/transform-messages.d.ts +8 -0
- package/dist/packages/ai/providers/transform-messages.js +155 -0
- package/dist/packages/ai/stream.d.ts +9 -0
- package/dist/packages/ai/stream.js +28 -0
- package/dist/packages/ai/types.d.ts +281 -0
- package/dist/packages/ai/types.js +2 -0
- package/dist/packages/ai/utils/event-stream.d.ts +21 -0
- package/dist/packages/ai/utils/event-stream.js +81 -0
- package/dist/packages/ai/utils/http-proxy.d.ts +1 -0
- package/dist/packages/ai/utils/http-proxy.js +15 -0
- package/dist/packages/ai/utils/json-parse.d.ts +9 -0
- package/dist/packages/ai/utils/json-parse.js +29 -0
- package/dist/packages/ai/utils/oauth/anthropic.d.ts +17 -0
- package/dist/packages/ai/utils/oauth/anthropic.js +104 -0
- package/dist/packages/ai/utils/oauth/github-copilot.d.ts +30 -0
- package/dist/packages/ai/utils/oauth/github-copilot.js +281 -0
- package/dist/packages/ai/utils/oauth/google-antigravity.d.ts +26 -0
- package/dist/packages/ai/utils/oauth/google-antigravity.js +373 -0
- package/dist/packages/ai/utils/oauth/google-gemini-cli.d.ts +26 -0
- package/dist/packages/ai/utils/oauth/google-gemini-cli.js +478 -0
- package/dist/packages/ai/utils/oauth/index.d.ts +62 -0
- package/dist/packages/ai/utils/oauth/index.js +133 -0
- package/dist/packages/ai/utils/oauth/openai-codex.d.ts +34 -0
- package/dist/packages/ai/utils/oauth/openai-codex.js +380 -0
- package/dist/packages/ai/utils/oauth/pkce.d.ts +13 -0
- package/dist/packages/ai/utils/oauth/pkce.js +31 -0
- package/dist/packages/ai/utils/oauth/types.d.ts +47 -0
- package/dist/packages/ai/utils/oauth/types.js +2 -0
- package/dist/packages/ai/utils/overflow.d.ts +52 -0
- package/dist/packages/ai/utils/overflow.js +115 -0
- package/dist/packages/ai/utils/sanitize-unicode.d.ts +22 -0
- package/dist/packages/ai/utils/sanitize-unicode.js +26 -0
- package/dist/packages/ai/utils/typebox-helpers.d.ts +17 -0
- package/dist/packages/ai/utils/typebox-helpers.js +21 -0
- package/dist/packages/ai/utils/validation.d.ts +18 -0
- package/dist/packages/ai/utils/validation.js +72 -0
- package/dist/packages/nano-mem/cli.js +21 -0
- package/dist/packages/nano-mem/dedup.d.ts +17 -0
- package/dist/packages/nano-mem/dedup.js +84 -0
- package/dist/packages/nano-mem/engine.d.ts +9 -0
- package/dist/packages/nano-mem/engine.js +79 -8
- package/dist/packages/nano-mem/full-insights-html.js +191 -191
- package/dist/packages/nano-mem/i18n.js +83 -55
- package/dist/packages/nano-mem/update.d.ts +21 -1
- package/dist/packages/nano-mem/update.js +35 -2
- package/dist/packages/nanomem/cli.d.ts +7 -0
- package/dist/packages/nanomem/cli.js +89 -0
- package/dist/packages/nanomem/config.d.ts +45 -0
- package/dist/packages/nanomem/config.js +47 -0
- package/dist/packages/nanomem/consolidation.d.ts +12 -0
- package/dist/packages/nanomem/consolidation.js +110 -0
- package/dist/packages/nanomem/engine.d.ts +66 -0
- package/dist/packages/nanomem/engine.js +491 -0
- package/dist/packages/nanomem/eviction.d.ts +15 -0
- package/dist/packages/nanomem/eviction.js +21 -0
- package/dist/packages/nanomem/extension.d.ts +10 -0
- package/dist/packages/nanomem/extension.js +263 -0
- package/dist/packages/nanomem/extraction.d.ts +9 -0
- package/dist/packages/nanomem/extraction.js +135 -0
- package/dist/packages/nanomem/full-insights-html.d.ts +7 -0
- package/dist/packages/nanomem/full-insights-html.js +311 -0
- package/dist/packages/nanomem/full-insights.d.ts +20 -0
- package/dist/packages/nanomem/full-insights.js +326 -0
- package/dist/packages/nanomem/i18n.d.ts +49 -0
- package/dist/packages/nanomem/i18n.js +168 -0
- package/dist/packages/nanomem/index.d.ts +17 -0
- package/dist/packages/nanomem/index.js +13 -0
- package/dist/packages/nanomem/insights-html.d.ts +7 -0
- package/dist/packages/nanomem/insights-html.js +430 -0
- package/dist/packages/nanomem/linking.d.ts +10 -0
- package/dist/packages/nanomem/linking.js +39 -0
- package/dist/packages/nanomem/package.json +10 -0
- package/dist/packages/nanomem/privacy.d.ts +15 -0
- package/dist/packages/nanomem/privacy.js +51 -0
- package/dist/packages/nanomem/scoring.d.ts +24 -0
- package/dist/packages/nanomem/scoring.js +62 -0
- package/dist/packages/nanomem/store.d.ts +15 -0
- package/dist/packages/nanomem/store.js +67 -0
- package/dist/packages/nanomem/types.d.ts +190 -0
- package/dist/packages/nanomem/types.js +6 -0
- package/dist/packages/nanomem/update.d.ts +13 -0
- package/dist/packages/nanomem/update.js +125 -0
- package/dist/packages/nanosoul/extension.d.ts +15 -0
- package/dist/packages/nanosoul/extension.js +39 -0
- package/dist/packages/tui/autocomplete.d.ts +50 -0
- package/dist/packages/tui/autocomplete.js +596 -0
- package/dist/packages/tui/components/box.d.ts +22 -0
- package/dist/packages/tui/components/box.js +104 -0
- package/dist/packages/tui/components/cancellable-loader.d.ts +22 -0
- package/dist/packages/tui/components/cancellable-loader.js +35 -0
- package/dist/packages/tui/components/editor.d.ts +205 -0
- package/dist/packages/tui/components/editor.js +1679 -0
- package/dist/packages/tui/components/image.d.ts +28 -0
- package/dist/packages/tui/components/image.js +69 -0
- package/dist/packages/tui/components/input.d.ts +37 -0
- package/dist/packages/tui/components/input.js +433 -0
- package/dist/packages/tui/components/loader.d.ts +21 -0
- package/dist/packages/tui/components/loader.js +49 -0
- package/dist/packages/tui/components/markdown.d.ts +95 -0
- package/dist/packages/tui/components/markdown.js +629 -0
- package/dist/packages/tui/components/select-list.d.ts +32 -0
- package/dist/packages/tui/components/select-list.js +152 -0
- package/dist/packages/tui/components/settings-list.d.ts +50 -0
- package/dist/packages/tui/components/settings-list.js +185 -0
- package/dist/packages/tui/components/spacer.d.ts +12 -0
- package/dist/packages/tui/components/spacer.js +23 -0
- package/dist/packages/tui/components/text.d.ts +19 -0
- package/dist/packages/tui/components/text.js +89 -0
- package/dist/packages/tui/components/truncated-text.d.ts +13 -0
- package/dist/packages/tui/components/truncated-text.js +51 -0
- package/dist/packages/tui/editor-component.d.ts +39 -0
- package/dist/packages/tui/editor-component.js +2 -0
- package/dist/packages/tui/fuzzy.d.ts +16 -0
- package/dist/packages/tui/fuzzy.js +107 -0
- package/dist/packages/tui/index.d.ts +23 -0
- package/dist/packages/tui/index.js +32 -0
- package/dist/packages/tui/keybindings.d.ts +39 -0
- package/dist/packages/tui/keybindings.js +114 -0
- package/dist/packages/tui/keys.d.ts +160 -0
- package/dist/packages/tui/keys.js +959 -0
- package/dist/packages/tui/kill-ring.d.ts +28 -0
- package/dist/packages/tui/kill-ring.js +44 -0
- package/dist/packages/tui/package.json +10 -0
- package/dist/packages/tui/stdin-buffer.d.ts +48 -0
- package/dist/packages/tui/stdin-buffer.js +317 -0
- package/dist/packages/tui/terminal-image.d.ts +68 -0
- package/dist/packages/tui/terminal-image.js +288 -0
- package/dist/packages/tui/terminal.d.ts +78 -0
- package/dist/packages/tui/terminal.js +249 -0
- package/dist/packages/tui/tui.d.ts +210 -0
- package/dist/packages/tui/tui.js +955 -0
- package/dist/packages/tui/undo-stack.d.ts +17 -0
- package/dist/packages/tui/undo-stack.js +25 -0
- package/dist/packages/tui/utils.d.ts +78 -0
- package/dist/packages/tui/utils.js +806 -0
- package/docs/APIKEY_COMMAND.md +2 -0
- package/docs/APIKEY_FIX_SUMMARY.md +1 -1
- package/docs/ARK_CODING_PLAN.md +51 -0
- package/docs/CHANGELOG.md +9 -0
- package/docs/NANOMEM_READ_WRITE.md +352 -0
- package/docs/QIANFAN_CODING_PLAN.md +52 -0
- package/docs/RELEASE_GUIDE.md +129 -129
- package/package.json +2 -2
|
@@ -12,23 +12,23 @@ export const API_KEY_GUIDANCE = {
|
|
|
12
12
|
serverName: "GitHub",
|
|
13
13
|
required: false,
|
|
14
14
|
envVar: "GITHUB_TOKEN",
|
|
15
|
-
instructions: `GitHub Token 用于访问 GitHub 仓库、issues 和 PRs。
|
|
16
|
-
|
|
17
|
-
**获取步骤:**
|
|
18
|
-
1. 访问 https://github.com/settings/tokens
|
|
19
|
-
2. 点击 "Generate new token" (classic)
|
|
20
|
-
3. 勾选权限:
|
|
21
|
-
- ✅ repo (Full control of private repositories)
|
|
22
|
-
- ✅ public_repo (Access public repositories)
|
|
23
|
-
4. 点击 "Generate token"
|
|
24
|
-
5. 复制 token (格式: ghp_xxxxxxxxxxxxxxxxxxxx)
|
|
25
|
-
6. 在 mcp.json 中配置:
|
|
26
|
-
{
|
|
27
|
-
"id": "github",
|
|
28
|
-
"enabled": true,
|
|
29
|
-
"env": {
|
|
30
|
-
"GITHUB_TOKEN": "你的token"
|
|
31
|
-
}
|
|
15
|
+
instructions: `GitHub Token 用于访问 GitHub 仓库、issues 和 PRs。
|
|
16
|
+
|
|
17
|
+
**获取步骤:**
|
|
18
|
+
1. 访问 https://github.com/settings/tokens
|
|
19
|
+
2. 点击 "Generate new token" (classic)
|
|
20
|
+
3. 勾选权限:
|
|
21
|
+
- ✅ repo (Full control of private repositories)
|
|
22
|
+
- ✅ public_repo (Access public repositories)
|
|
23
|
+
4. 点击 "Generate token"
|
|
24
|
+
5. 复制 token (格式: ghp_xxxxxxxxxxxxxxxxxxxx)
|
|
25
|
+
6. 在 mcp.json 中配置:
|
|
26
|
+
{
|
|
27
|
+
"id": "github",
|
|
28
|
+
"enabled": true,
|
|
29
|
+
"env": {
|
|
30
|
+
"GITHUB_TOKEN": "你的token"
|
|
31
|
+
}
|
|
32
32
|
}`,
|
|
33
33
|
getKeyUrl: "https://github.com/settings/tokens",
|
|
34
34
|
freeTier: "✅ 完全免费",
|
|
@@ -39,20 +39,20 @@ export const API_KEY_GUIDANCE = {
|
|
|
39
39
|
serverName: "Brave Search",
|
|
40
40
|
required: false,
|
|
41
41
|
envVar: "BRAVE_API_KEY",
|
|
42
|
-
instructions: `Brave Search API Key 用于网页搜索功能。
|
|
43
|
-
|
|
44
|
-
**获取步骤:**
|
|
45
|
-
1. 访问 https://api.search.brave.com/app/keys
|
|
46
|
-
2. 注册账号(或登录)
|
|
47
|
-
3. 点击 "Create API Key"
|
|
48
|
-
4. 复制 API Key (格式: BSxxxxx)
|
|
49
|
-
5. 在 mcp.json 中配置:
|
|
50
|
-
{
|
|
51
|
-
"id": "brave-search",
|
|
52
|
-
"enabled": true,
|
|
53
|
-
"env": {
|
|
54
|
-
"BRAVE_API_KEY": "你的API key"
|
|
55
|
-
}
|
|
42
|
+
instructions: `Brave Search API Key 用于网页搜索功能。
|
|
43
|
+
|
|
44
|
+
**获取步骤:**
|
|
45
|
+
1. 访问 https://api.search.brave.com/app/keys
|
|
46
|
+
2. 注册账号(或登录)
|
|
47
|
+
3. 点击 "Create API Key"
|
|
48
|
+
4. 复制 API Key (格式: BSxxxxx)
|
|
49
|
+
5. 在 mcp.json 中配置:
|
|
50
|
+
{
|
|
51
|
+
"id": "brave-search",
|
|
52
|
+
"enabled": true,
|
|
53
|
+
"env": {
|
|
54
|
+
"BRAVE_API_KEY": "你的API key"
|
|
55
|
+
}
|
|
56
56
|
}`,
|
|
57
57
|
getKeyUrl: "https://api.search.brave.com/app/keys",
|
|
58
58
|
freeTier: "✅ 免费额度: 每月 2000 次查询",
|
|
@@ -63,19 +63,19 @@ export const API_KEY_GUIDANCE = {
|
|
|
63
63
|
serverName: "PostgreSQL",
|
|
64
64
|
required: false,
|
|
65
65
|
envVar: "POSTGRES_CONNECTION_STRING",
|
|
66
|
-
instructions: `PostgreSQL 连接字符串用于连接本地数据库。
|
|
67
|
-
|
|
68
|
-
**配置步骤:**
|
|
69
|
-
1. 确保已安装 PostgreSQL
|
|
70
|
-
2. 准备连接字符串,格式:
|
|
71
|
-
postgresql://user:password@localhost:5432/dbname
|
|
72
|
-
3. 在 mcp.json 中配置:
|
|
73
|
-
{
|
|
74
|
-
"id": "postgres",
|
|
75
|
-
"enabled": true,
|
|
76
|
-
"env": {
|
|
77
|
-
"POSTGRES_CONNECTION_STRING": "你的连接字符串"
|
|
78
|
-
}
|
|
66
|
+
instructions: `PostgreSQL 连接字符串用于连接本地数据库。
|
|
67
|
+
|
|
68
|
+
**配置步骤:**
|
|
69
|
+
1. 确保已安装 PostgreSQL
|
|
70
|
+
2. 准备连接字符串,格式:
|
|
71
|
+
postgresql://user:password@localhost:5432/dbname
|
|
72
|
+
3. 在 mcp.json 中配置:
|
|
73
|
+
{
|
|
74
|
+
"id": "postgres",
|
|
75
|
+
"enabled": true,
|
|
76
|
+
"env": {
|
|
77
|
+
"POSTGRES_CONNECTION_STRING": "你的连接字符串"
|
|
78
|
+
}
|
|
79
79
|
}`,
|
|
80
80
|
freeTier: "✅ 完全免费 (本地数据库)",
|
|
81
81
|
alternative: "使用 SQLite (默认启用)",
|
|
@@ -12,8 +12,8 @@ export declare const clearApiKeyCache: typeof clearConfigValueCache;
|
|
|
12
12
|
export interface ModelRegistryOptions {
|
|
13
13
|
/** When true, only load models from models.json (no built-in providers). Used by NanoPencil. */
|
|
14
14
|
useOnlyCustomModels?: boolean;
|
|
15
|
-
/** Provider id for which apiKey is optional in models.json (key stored in auth.json later). Used by NanoPencil. */
|
|
16
|
-
allowOptionalApiKeyForProvider?: string;
|
|
15
|
+
/** Provider id(s) for which apiKey is optional in models.json (key stored in auth.json later). Used by NanoPencil. */
|
|
16
|
+
allowOptionalApiKeyForProvider?: string | string[];
|
|
17
17
|
}
|
|
18
18
|
export declare class ModelRegistry {
|
|
19
19
|
readonly authStorage: AuthStorage;
|
|
@@ -309,8 +309,11 @@ export class ModelRegistry {
|
|
|
309
309
|
if (!providerConfig.baseUrl) {
|
|
310
310
|
throw new Error(`Provider ${providerName}: "baseUrl" is required when defining custom models.`);
|
|
311
311
|
}
|
|
312
|
-
const
|
|
313
|
-
|
|
312
|
+
const allowed = this.allowOptionalApiKeyForProvider !== undefined &&
|
|
313
|
+
(Array.isArray(this.allowOptionalApiKeyForProvider)
|
|
314
|
+
? this.allowOptionalApiKeyForProvider.includes(providerName)
|
|
315
|
+
: providerName === this.allowOptionalApiKeyForProvider);
|
|
316
|
+
const apiKeyOptional = !!allowed;
|
|
314
317
|
if (!apiKeyOptional && !providerConfig.apiKey) {
|
|
315
318
|
throw new Error(`Provider ${providerName}: "apiKey" is required when defining custom models.`);
|
|
316
319
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Usage } from "@pencil-agent/ai";
|
|
2
|
+
export interface UsageTotals {
|
|
3
|
+
input: number;
|
|
4
|
+
output: number;
|
|
5
|
+
cacheRead: number;
|
|
6
|
+
cacheWrite: number;
|
|
7
|
+
cost: number;
|
|
8
|
+
}
|
|
9
|
+
export interface UsageStats {
|
|
10
|
+
total: UsageTotals;
|
|
11
|
+
byDay: Record<string, UsageTotals>;
|
|
12
|
+
byMonth: Record<string, UsageTotals>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Tracks token usage across all sessions and runs.
|
|
16
|
+
*
|
|
17
|
+
* Writes an append-only JSONL log (usage.jsonl) plus a small running total file
|
|
18
|
+
* (usage-total.json) for fast "global total" queries.
|
|
19
|
+
*/
|
|
20
|
+
export declare class UsageTracker {
|
|
21
|
+
private agentDir;
|
|
22
|
+
private usageLogPath;
|
|
23
|
+
private totalPath;
|
|
24
|
+
constructor(agentDir: string);
|
|
25
|
+
/**
|
|
26
|
+
* Record usage for a single assistant response.
|
|
27
|
+
*
|
|
28
|
+
* Safe to call frequently; errors are swallowed so as not to affect the agent.
|
|
29
|
+
*/
|
|
30
|
+
record(usage: Usage, timestampMs?: number): void;
|
|
31
|
+
/**
|
|
32
|
+
* Get aggregated usage statistics:
|
|
33
|
+
* - total: global totals across all time
|
|
34
|
+
* - byDay: grouped by YYYY-MM-DD
|
|
35
|
+
* - byMonth: grouped by YYYY-MM
|
|
36
|
+
*/
|
|
37
|
+
getUsageStats(): UsageStats;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=usage-tracker.d.ts.map
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { mkdirSync, existsSync, readFileSync, writeFileSync, appendFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
function emptyTotals() {
|
|
4
|
+
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
|
|
5
|
+
}
|
|
6
|
+
function addInto(target, delta) {
|
|
7
|
+
target.input += delta.input;
|
|
8
|
+
target.output += delta.output;
|
|
9
|
+
target.cacheRead += delta.cacheRead;
|
|
10
|
+
target.cacheWrite += delta.cacheWrite;
|
|
11
|
+
target.cost += delta.cost;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Tracks token usage across all sessions and runs.
|
|
15
|
+
*
|
|
16
|
+
* Writes an append-only JSONL log (usage.jsonl) plus a small running total file
|
|
17
|
+
* (usage-total.json) for fast "global total" queries.
|
|
18
|
+
*/
|
|
19
|
+
export class UsageTracker {
|
|
20
|
+
agentDir;
|
|
21
|
+
usageLogPath;
|
|
22
|
+
totalPath;
|
|
23
|
+
constructor(agentDir) {
|
|
24
|
+
this.agentDir = agentDir;
|
|
25
|
+
this.usageLogPath = join(agentDir, "usage.jsonl");
|
|
26
|
+
this.totalPath = join(agentDir, "usage-total.json");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Record usage for a single assistant response.
|
|
30
|
+
*
|
|
31
|
+
* Safe to call frequently; errors are swallowed so as not to affect the agent.
|
|
32
|
+
*/
|
|
33
|
+
record(usage, timestampMs) {
|
|
34
|
+
try {
|
|
35
|
+
// Ensure base directory exists
|
|
36
|
+
if (!existsSync(this.agentDir)) {
|
|
37
|
+
mkdirSync(this.agentDir, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
const date = timestampMs ? new Date(timestampMs) : new Date();
|
|
40
|
+
const iso = date.toISOString();
|
|
41
|
+
const day = iso.slice(0, 10); // YYYY-MM-DD
|
|
42
|
+
const month = iso.slice(0, 7); // YYYY-MM
|
|
43
|
+
const delta = {
|
|
44
|
+
input: usage.input ?? 0,
|
|
45
|
+
output: usage.output ?? 0,
|
|
46
|
+
cacheRead: usage.cacheRead ?? 0,
|
|
47
|
+
cacheWrite: usage.cacheWrite ?? 0,
|
|
48
|
+
cost: usage.cost?.total ?? 0,
|
|
49
|
+
};
|
|
50
|
+
// Append one line to usage.jsonl
|
|
51
|
+
const logEntry = JSON.stringify({
|
|
52
|
+
date: day,
|
|
53
|
+
month,
|
|
54
|
+
input: delta.input,
|
|
55
|
+
output: delta.output,
|
|
56
|
+
cacheRead: delta.cacheRead,
|
|
57
|
+
cacheWrite: delta.cacheWrite,
|
|
58
|
+
cost: delta.cost,
|
|
59
|
+
});
|
|
60
|
+
appendFileSync(this.usageLogPath, logEntry + "\n");
|
|
61
|
+
// Update running total (best-effort)
|
|
62
|
+
let total = emptyTotals();
|
|
63
|
+
if (existsSync(this.totalPath)) {
|
|
64
|
+
try {
|
|
65
|
+
const raw = readFileSync(this.totalPath, "utf8");
|
|
66
|
+
const parsed = JSON.parse(raw);
|
|
67
|
+
total = {
|
|
68
|
+
input: parsed.input ?? 0,
|
|
69
|
+
output: parsed.output ?? 0,
|
|
70
|
+
cacheRead: parsed.cacheRead ?? 0,
|
|
71
|
+
cacheWrite: parsed.cacheWrite ?? 0,
|
|
72
|
+
cost: parsed.cost ?? 0,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Ignore parse errors and start fresh
|
|
77
|
+
total = emptyTotals();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
addInto(total, delta);
|
|
81
|
+
writeFileSync(this.totalPath, JSON.stringify(total));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Swallow all errors - usage tracking must never break the agent
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get aggregated usage statistics:
|
|
89
|
+
* - total: global totals across all time
|
|
90
|
+
* - byDay: grouped by YYYY-MM-DD
|
|
91
|
+
* - byMonth: grouped by YYYY-MM
|
|
92
|
+
*/
|
|
93
|
+
getUsageStats() {
|
|
94
|
+
const total = emptyTotals();
|
|
95
|
+
const byDay = Object.create(null);
|
|
96
|
+
const byMonth = Object.create(null);
|
|
97
|
+
// Load global total if available
|
|
98
|
+
if (existsSync(this.totalPath)) {
|
|
99
|
+
try {
|
|
100
|
+
const raw = readFileSync(this.totalPath, "utf8");
|
|
101
|
+
const parsed = JSON.parse(raw);
|
|
102
|
+
total.input = parsed.input ?? 0;
|
|
103
|
+
total.output = parsed.output ?? 0;
|
|
104
|
+
total.cacheRead = parsed.cacheRead ?? 0;
|
|
105
|
+
total.cacheWrite = parsed.cacheWrite ?? 0;
|
|
106
|
+
total.cost = parsed.cost ?? 0;
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Ignore and fall back to computing from log
|
|
110
|
+
total.input = 0;
|
|
111
|
+
total.output = 0;
|
|
112
|
+
total.cacheRead = 0;
|
|
113
|
+
total.cacheWrite = 0;
|
|
114
|
+
total.cost = 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (existsSync(this.usageLogPath)) {
|
|
118
|
+
try {
|
|
119
|
+
const raw = readFileSync(this.usageLogPath, "utf8");
|
|
120
|
+
const lines = raw.split("\n");
|
|
121
|
+
for (const line of lines) {
|
|
122
|
+
const trimmed = line.trim();
|
|
123
|
+
if (!trimmed)
|
|
124
|
+
continue;
|
|
125
|
+
let entry;
|
|
126
|
+
try {
|
|
127
|
+
entry = JSON.parse(trimmed);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const day = typeof entry.date === "string" ? entry.date : undefined;
|
|
133
|
+
const month = typeof entry.month === "string" ? entry.month : undefined;
|
|
134
|
+
const delta = {
|
|
135
|
+
input: Number(entry.input) || 0,
|
|
136
|
+
output: Number(entry.output) || 0,
|
|
137
|
+
cacheRead: Number(entry.cacheRead) || 0,
|
|
138
|
+
cacheWrite: Number(entry.cacheWrite) || 0,
|
|
139
|
+
cost: Number(entry.cost) || 0,
|
|
140
|
+
};
|
|
141
|
+
// If total file was missing or corrupt, rebuild it from log
|
|
142
|
+
if (!existsSync(this.totalPath)) {
|
|
143
|
+
addInto(total, delta);
|
|
144
|
+
}
|
|
145
|
+
if (day) {
|
|
146
|
+
if (!byDay[day])
|
|
147
|
+
byDay[day] = emptyTotals();
|
|
148
|
+
addInto(byDay[day], delta);
|
|
149
|
+
}
|
|
150
|
+
if (month) {
|
|
151
|
+
if (!byMonth[month])
|
|
152
|
+
byMonth[month] = emptyTotals();
|
|
153
|
+
addInto(byMonth[month], delta);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// If we had to rebuild total, persist it for next time
|
|
157
|
+
if (!existsSync(this.totalPath)) {
|
|
158
|
+
writeFileSync(this.totalPath, JSON.stringify(total));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Ignore log read errors
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return { total, byDay, byMonth };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=usage-tracker.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Reach extension - installs and configures Agent Reach
|
|
3
|
+
* Adds /link-world command to give the AI agent internet access capabilities
|
|
4
|
+
*/
|
|
5
|
+
import type { ExtensionAPI } from "../../core/extensions/types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Agent Reach extension factory (default export)
|
|
8
|
+
*/
|
|
9
|
+
export default function agentReachExtension(pi: ExtensionAPI): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Reach extension - installs and configures Agent Reach
|
|
3
|
+
* Adds /link-world command to give the AI agent internet access capabilities
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Agent Reach extension factory (default export)
|
|
7
|
+
*/
|
|
8
|
+
export default async function agentReachExtension(pi) {
|
|
9
|
+
// Register the /link-world command
|
|
10
|
+
pi.registerCommand("link-world", {
|
|
11
|
+
description: "Install Agent Reach to give the AI agent full internet access (Twitter, YouTube, Bilibili, Reddit, GitHub, 小红书, 抖音, etc.)",
|
|
12
|
+
handler: async (_args, ctx) => {
|
|
13
|
+
await handleLinkWorld(ctx, pi);
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
;
|
|
18
|
+
/**
|
|
19
|
+
* Handle the /link-world command
|
|
20
|
+
* Installs Agent Reach and configures it
|
|
21
|
+
*/
|
|
22
|
+
async function handleLinkWorld(_ctx, pi) {
|
|
23
|
+
// Send initial message
|
|
24
|
+
pi.sendMessage({
|
|
25
|
+
customType: "agent-reach-install",
|
|
26
|
+
content: [
|
|
27
|
+
{
|
|
28
|
+
type: "text",
|
|
29
|
+
text: `🌐 **正在安装 Agent Reach...**
|
|
30
|
+
|
|
31
|
+
Agent Reach 是一个让 AI 代理具备互联网访问能力的工具,支持以下平台:
|
|
32
|
+
- **Twitter/X** - 搜索和发布推文
|
|
33
|
+
- **YouTube** - 视频信息获取
|
|
34
|
+
- **Bilibili** - 视频信息获取
|
|
35
|
+
- **Reddit** - 帖子读取
|
|
36
|
+
- **GitHub** - 代码仓库搜索
|
|
37
|
+
- **小红书** - 帖子搜索
|
|
38
|
+
- **抖音** - 视频解析
|
|
39
|
+
- **LinkedIn** - 职位信息
|
|
40
|
+
- **Boss直聘** - 职位搜索
|
|
41
|
+
- **Exa Search** - AI 网页搜索
|
|
42
|
+
|
|
43
|
+
正在执行安装...`,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
display: true,
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
// Step 1: Install Agent Reach via pip
|
|
50
|
+
pi.sendMessage({
|
|
51
|
+
customType: "agent-reach-step",
|
|
52
|
+
content: [{ type: "text", text: "\n📦 **步骤 1/3**: 安装 Agent Reach..." }],
|
|
53
|
+
display: true,
|
|
54
|
+
});
|
|
55
|
+
const installResult = await pi.exec("pip", ["install", "https://github.com/Panniantong/agent-reach/archive/main.zip"]);
|
|
56
|
+
if (installResult.code !== 0) {
|
|
57
|
+
throw new Error(`安装失败: ${installResult.stderr}`);
|
|
58
|
+
}
|
|
59
|
+
pi.sendMessage({
|
|
60
|
+
customType: "agent-reach-step",
|
|
61
|
+
content: [{ type: "text", text: "✅ Agent Reach 安装成功" }],
|
|
62
|
+
display: true,
|
|
63
|
+
});
|
|
64
|
+
// Step 2: Run agent-reach install
|
|
65
|
+
pi.sendMessage({
|
|
66
|
+
customType: "agent-reach-step",
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: "text",
|
|
70
|
+
text: "\n⚙️ **步骤 2/3**: 配置环境(自动检测并安装依赖)...",
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
display: true,
|
|
74
|
+
});
|
|
75
|
+
const configResult = await pi.exec("agent-reach", ["install", "--env=auto"]);
|
|
76
|
+
if (configResult.code !== 0) {
|
|
77
|
+
// If auto-install fails, try safe mode
|
|
78
|
+
pi.sendMessage({
|
|
79
|
+
customType: "agent-reach-step",
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: "text",
|
|
83
|
+
text: "⚠️ 自动安装遇到问题,尝试安全模式(不会自动安装系统包)...",
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
display: true,
|
|
87
|
+
});
|
|
88
|
+
const safeResult = await pi.exec("agent-reach", ["install", "--env=auto", "--safe"]);
|
|
89
|
+
if (safeResult.code !== 0) {
|
|
90
|
+
pi.sendMessage({
|
|
91
|
+
customType: "agent-reach-warning",
|
|
92
|
+
content: [
|
|
93
|
+
{
|
|
94
|
+
type: "text",
|
|
95
|
+
text: `⚠️ 配置过程中遇到一些问题:
|
|
96
|
+
|
|
97
|
+
\`\`\`
|
|
98
|
+
${safeResult.stderr}
|
|
99
|
+
\`\`\`
|
|
100
|
+
|
|
101
|
+
你可以稍后手动运行以下命令完成配置:
|
|
102
|
+
\`\`\`bash
|
|
103
|
+
agent-reach doctor
|
|
104
|
+
\`\`\`
|
|
105
|
+
`,
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
display: true,
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
pi.sendMessage({
|
|
114
|
+
customType: "agent-reach-step",
|
|
115
|
+
content: [{ type: "text", text: "✅ 环境配置完成" }],
|
|
116
|
+
display: true,
|
|
117
|
+
});
|
|
118
|
+
// Step 3: Run agent-reach doctor to show status
|
|
119
|
+
pi.sendMessage({
|
|
120
|
+
customType: "agent-reach-step",
|
|
121
|
+
content: [
|
|
122
|
+
{ type: "text", text: "\n🏥 **步骤 3/3**: 检查各通道状态..." },
|
|
123
|
+
],
|
|
124
|
+
display: true,
|
|
125
|
+
});
|
|
126
|
+
const doctorResult = await pi.exec("agent-reach", ["doctor"]);
|
|
127
|
+
// Show doctor results
|
|
128
|
+
pi.sendMessage({
|
|
129
|
+
customType: "agent-reach-result",
|
|
130
|
+
content: [
|
|
131
|
+
{
|
|
132
|
+
type: "text",
|
|
133
|
+
text: `📊 **通道状态报告:**
|
|
134
|
+
|
|
135
|
+
\`\`\`
|
|
136
|
+
${doctorResult.stdout}
|
|
137
|
+
\`\`\`
|
|
138
|
+
`,
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
display: true,
|
|
142
|
+
});
|
|
143
|
+
// Final message with next steps
|
|
144
|
+
pi.sendMessage({
|
|
145
|
+
customType: "agent-reach-complete",
|
|
146
|
+
content: [
|
|
147
|
+
{
|
|
148
|
+
type: "text",
|
|
149
|
+
text: `
|
|
150
|
+
🎉 **Agent Reach 安装完成!**
|
|
151
|
+
|
|
152
|
+
**可用命令:**
|
|
153
|
+
- \`agent-reach doctor\` - 查看通道状态
|
|
154
|
+
- \`agent-reach watch\` - 快速健康检查
|
|
155
|
+
- \`agent-reach check-update\` - 检查更新
|
|
156
|
+
|
|
157
|
+
**配置额外功能(可选):**
|
|
158
|
+
部分平台需要额外配置才能使用:
|
|
159
|
+
|
|
160
|
+
🔑 **Twitter** - 需要 Cookie:
|
|
161
|
+
\`\`\`bash
|
|
162
|
+
agent-reach configure twitter-cookies "YOUR_COOKIE_STRING"
|
|
163
|
+
\`\`\`
|
|
164
|
+
|
|
165
|
+
🔑 **小红书** - 需要 Docker + MCP 服务:
|
|
166
|
+
\`\`\`bash
|
|
167
|
+
docker run -d --name xiaohongshu-mcp -p 18060:18060 xpzouying/xiaohongshu-mcp
|
|
168
|
+
mcporter config add xiaohongshu http://localhost:18060/mcp
|
|
169
|
+
\`\`\`
|
|
170
|
+
|
|
171
|
+
🔑 **抖音** - 需要安装 MCP 服务:
|
|
172
|
+
\`\`\`bash
|
|
173
|
+
pip install douyin-mcp-server
|
|
174
|
+
# 启动服务(详见 Agent Reach 文档)
|
|
175
|
+
\`\`\`
|
|
176
|
+
|
|
177
|
+
🌐 **代理配置(如需要):**
|
|
178
|
+
\`\`\`bash
|
|
179
|
+
agent-reach configure proxy http://user:pass@ip:port
|
|
180
|
+
\`\`\`
|
|
181
|
+
|
|
182
|
+
详细文档:https://github.com/Panniantong/agent-reach
|
|
183
|
+
`,
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
display: true,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
pi.sendMessage({
|
|
191
|
+
customType: "agent-reach-error",
|
|
192
|
+
content: [
|
|
193
|
+
{
|
|
194
|
+
type: "text",
|
|
195
|
+
text: `❌ **安装失败**
|
|
196
|
+
|
|
197
|
+
错误信息: ${error instanceof Error ? error.message : String(error)}
|
|
198
|
+
|
|
199
|
+
请检查:
|
|
200
|
+
1. 是否已安装 Python 和 pip
|
|
201
|
+
2. 网络连接是否正常
|
|
202
|
+
3. 是否有足够的权限
|
|
203
|
+
|
|
204
|
+
你可以手动安装:
|
|
205
|
+
\`\`\`bash
|
|
206
|
+
pip install https://github.com/Panniantong/agent-reach/archive/main.zip
|
|
207
|
+
agent-reach install --env=auto
|
|
208
|
+
\`\`\`
|
|
209
|
+
`,
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
display: true,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* link-world 扩展:执行 /link-world 时让 AI 读取同目录下的安装文档并按要求安装。
|
|
3
|
+
* 安装后自动提供 internet-search Skill。
|
|
3
4
|
*/
|
|
4
|
-
import { readFileSync } from "node:fs";
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
6
|
import { dirname, join } from "node:path";
|
|
6
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { execSync } from "child_process";
|
|
7
9
|
import { Box, Container, Spacer, Text } from "@pencil-agent/tui";
|
|
8
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
11
|
const DOC_PATH = join(__dirname, "linkworld.md");
|
|
12
|
+
const SKILL_PATH = join(__dirname, "skills", "internet-search.md");
|
|
10
13
|
const LINK_WORLD_CUSTOM_TYPE = "link-world-install";
|
|
11
14
|
function getInstallDoc() {
|
|
12
15
|
try {
|
|
@@ -16,6 +19,19 @@ function getInstallDoc() {
|
|
|
16
19
|
return "";
|
|
17
20
|
}
|
|
18
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* 检查 agent-reach 是否已安装
|
|
24
|
+
*/
|
|
25
|
+
function isAgentReachInstalled() {
|
|
26
|
+
try {
|
|
27
|
+
// 检查 agent-reach CLI 是否可用
|
|
28
|
+
execSync("agent-reach --version", { encoding: "utf-8", stdio: "pipe" });
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
19
35
|
export default function linkWorldExtension(pi) {
|
|
20
36
|
/** TUI 仅显示简短提示,不展示完整安装文档内容 */
|
|
21
37
|
pi.registerMessageRenderer(LINK_WORLD_CUSTOM_TYPE, (message, _options, theme) => {
|
|
@@ -29,6 +45,22 @@ export default function linkWorldExtension(pi) {
|
|
|
29
45
|
container.addChild(box);
|
|
30
46
|
return container;
|
|
31
47
|
});
|
|
48
|
+
// 注册 resources_discover 事件:当 agent-reach 已安装时,提供 internet-search skill
|
|
49
|
+
pi.on("resources_discover", async (_event) => {
|
|
50
|
+
// 检查 agent-reach 是否已安装
|
|
51
|
+
if (!isAgentReachInstalled()) {
|
|
52
|
+
// 未安装,不提供 skill
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
// 检查 skill 文件是否存在
|
|
56
|
+
if (!existsSync(SKILL_PATH)) {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
// 返回 skill 路径
|
|
60
|
+
return {
|
|
61
|
+
skillPaths: [SKILL_PATH],
|
|
62
|
+
};
|
|
63
|
+
});
|
|
32
64
|
pi.registerCommand("link-world", {
|
|
33
65
|
description: "安装 link-world,为 AI 提供互联网访问(Twitter、YouTube、Bilibili、小红书、抖音等)",
|
|
34
66
|
handler: async (_args, _ctx) => {
|
package/dist/main.js
CHANGED
|
@@ -30,7 +30,7 @@ import { allTools } from "./core/tools/index.js";
|
|
|
30
30
|
import { runMigrations, showDeprecationWarnings } from "./migrations.js";
|
|
31
31
|
import { InteractiveMode, runPrintMode, runRpcMode } from "./modes/index.js";
|
|
32
32
|
import { initTheme, stopThemeWatcher } from "./modes/interactive/theme/theme.js";
|
|
33
|
-
import { ensureNanopencilCodingPlanAuth, ensureNanopencilDefaultConfig, NANOPENCIL_DEFAULT_PROVIDER, } from "./nanopencil-defaults.js";
|
|
33
|
+
import { ensureNanopencilCodingPlanAuth, ensureNanopencilDefaultConfig, NANOPENCIL_ARK_CODING_PROVIDER, NANOPENCIL_DEFAULT_PROVIDER, NANOPENCIL_QIANFAN_CODING_PROVIDER, } from "./nanopencil-defaults.js";
|
|
34
34
|
import { getNanopencilDefaultExtensionPaths } from "./pencil-mem-integration.js";
|
|
35
35
|
// Check if running in development mode (not production)
|
|
36
36
|
const isDevelopment = process.env.NODE_ENV !== "production";
|
|
@@ -507,7 +507,14 @@ export async function main(args) {
|
|
|
507
507
|
}
|
|
508
508
|
}
|
|
509
509
|
const modelRegistry = new ModelRegistry(authStorage, getModelsPath(), APP_NAME === "nanopencil"
|
|
510
|
-
? {
|
|
510
|
+
? {
|
|
511
|
+
useOnlyCustomModels: true,
|
|
512
|
+
allowOptionalApiKeyForProvider: [
|
|
513
|
+
NANOPENCIL_DEFAULT_PROVIDER,
|
|
514
|
+
NANOPENCIL_QIANFAN_CODING_PROVIDER,
|
|
515
|
+
NANOPENCIL_ARK_CODING_PROVIDER,
|
|
516
|
+
],
|
|
517
|
+
}
|
|
511
518
|
: {});
|
|
512
519
|
const defaultExtPaths = APP_NAME === "nanopencil" ? getNanopencilDefaultExtensionPaths() : [];
|
|
513
520
|
const resourceLoader = new DefaultResourceLoader({
|