u1s1-cli 1.9.0 → 1.11.0
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/README.md +16 -4
- package/dist/agent-setup.d.ts +8 -2
- package/dist/agent-setup.js +8 -4
- package/dist/config.d.ts +35 -0
- package/dist/config.js +44 -5
- package/dist/context-usage.d.ts +18 -0
- package/dist/context-usage.js +47 -0
- package/dist/index.js +25 -3
- package/dist/subagent.d.ts +1 -1
- package/dist/subagent.js +1 -1
- package/dist/tools.js +1 -1
- package/dist/usage.js +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# u1s1 — 有一说一,最省心的 AI 编程搭子
|
|
2
2
|
|
|
3
|
-
在终端里用中文说需求,AI 帮你读文件、改代码、跑命令。不用买模型、不用配 API、不用懂那些名词,默认 DeepSeek
|
|
3
|
+
在终端里用中文说需求,AI 帮你读文件、改代码、跑命令。不用买模型、不用配 API、不用懂那些名词,默认 DeepSeek Flash **每天免费 $2**(北京时间 0 点恢复),新用户另送一次性 $10 加量。
|
|
4
4
|
|
|
5
5
|
## 三步开始
|
|
6
6
|
|
|
@@ -46,14 +46,26 @@ u1s1
|
|
|
46
46
|
| `u1s1 import` | 从 Claude Code / Codex 导入历史对话,之后 `/resume` 就能接着聊 |
|
|
47
47
|
| `u1s1 login` / `u1s1 logout` | 登录 / 退出 |
|
|
48
48
|
|
|
49
|
+
## 长会话自动压缩
|
|
50
|
+
|
|
51
|
+
对话越长,每一轮上传的历史越多,回复会变慢、也更容易出错。u1s1 会在上下文接近 **200K token** 时自动压缩(把早期对话浓缩成摘要,最近 2 万 token 原文保留),压缩时界面有提示;`/context` 可以随时看当前占用、预算和触发点,`/compact` 可以手动压缩。
|
|
52
|
+
|
|
53
|
+
这只改变压缩时机,不改变模型能力。想调整或关闭,编辑 `~/.u1s1/agent/settings.json`:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{ "compaction": { "maxContextTokens": 200000 } }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`0` 表示不限(按模型自身窗口,如 DeepSeek Flash 的 1M)。改完重启 u1s1 生效。
|
|
60
|
+
|
|
49
61
|
## 在终端粘贴图片
|
|
50
62
|
|
|
51
|
-
|
|
63
|
+
默认模型 DeepSeek Flash 支持视觉输入,复制截图或图片后,在 u1s1 输入框按 `Ctrl+V` 即可附加图片。macOS 这里也使用 `Ctrl+V`;`Cmd+V` 由 Terminal/iTerm 接管,只适合粘贴文本,无法把剪贴板图片交给 CLI。
|
|
52
64
|
|
|
53
65
|
## 有一说一
|
|
54
66
|
|
|
55
|
-
- **背后模型**:默认 DeepSeek
|
|
56
|
-
- **怎么收费**:DeepSeek
|
|
67
|
+
- **背后模型**:默认 DeepSeek Flash(1M 上下文,每天免费 $2);难题可随时 `u1s1 model grok` 切 Grok 4.6。对话里 `/model` 也会记住,下次启动还是这个。
|
|
68
|
+
- **怎么收费**:DeepSeek Flash 每天有 $2 免费用量,北京时间 0 点恢复且不累计。免费用完或切换其他模型后,按 API 实际成本从永久余额扣,不加价;新用户另送一次性 $10 加量。
|
|
57
69
|
- **额度不够**:邀请朋友,你俩各得 $1 永久加量 → [u1s1.io/dashboard](https://u1s1.io/dashboard)
|
|
58
70
|
- **内核**:基于开源的 [pi](https://pi.dev) coding agent,会话管理、斜杠命令、皮肤等能力全都有。
|
|
59
71
|
|
package/dist/agent-setup.d.ts
CHANGED
|
@@ -79,8 +79,14 @@ export declare function writeCompactUiExtension(outputDir?: string): void;
|
|
|
79
79
|
* 其他 provider 的凭据原样保留;文件损坏时不动它,交给 SDK 自己报错。
|
|
80
80
|
*/
|
|
81
81
|
export declare function ensureAuthCredential(): void;
|
|
82
|
-
/**
|
|
83
|
-
|
|
82
|
+
/**
|
|
83
|
+
* pi provider 条目里的模型形状(models.json 与 registerProvider 共用)。
|
|
84
|
+
* contextWindow 不是模型真实窗口而是自动压缩预算(见 effectiveContextWindow):
|
|
85
|
+
* options.maxContextTokens 显式传 undefined 表示「用户没设」(测试用),不传则读 settings.json。
|
|
86
|
+
*/
|
|
87
|
+
export declare function toProviderModels(models: ModelDef[], options?: {
|
|
88
|
+
maxContextTokens?: number;
|
|
89
|
+
}): {
|
|
84
90
|
id: string;
|
|
85
91
|
name: string;
|
|
86
92
|
reasoning: boolean;
|
package/dist/agent-setup.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
|
-
import { agentDir, CUSTOM_ENDPOINTS, ENDPOINT_ID_RE, endpointKeyEnvName, MODELS, PROVIDER_ID, UNKNOWN_MODEL_COST, VERSION, } from "./config.js";
|
|
4
|
+
import { agentDir, CUSTOM_ENDPOINTS, ENDPOINT_ID_RE, effectiveContextWindow, endpointKeyEnvName, MODELS, readCompactionBudgetSetting, PROVIDER_ID, UNKNOWN_MODEL_COST, VERSION, } from "./config.js";
|
|
5
5
|
const BRAND_APPEND = `## u1s1
|
|
6
6
|
|
|
7
7
|
You are u1s1 — a plain-spoken AI coding buddy for programming beginners. Most users are unfamiliar with jargon:
|
|
@@ -510,8 +510,12 @@ export function ensureAuthCredential() {
|
|
|
510
510
|
root[PROVIDER_ID] = { type: "api_key", key: "$U1S1_API_KEY" };
|
|
511
511
|
writeFileSync(p, JSON.stringify(root, null, 2) + "\n", { mode: 0o600 });
|
|
512
512
|
}
|
|
513
|
-
/**
|
|
514
|
-
|
|
513
|
+
/**
|
|
514
|
+
* pi provider 条目里的模型形状(models.json 与 registerProvider 共用)。
|
|
515
|
+
* contextWindow 不是模型真实窗口而是自动压缩预算(见 effectiveContextWindow):
|
|
516
|
+
* options.maxContextTokens 显式传 undefined 表示「用户没设」(测试用),不传则读 settings.json。
|
|
517
|
+
*/
|
|
518
|
+
export function toProviderModels(models, options = { maxContextTokens: readCompactionBudgetSetting() }) {
|
|
515
519
|
return models.map((m) => {
|
|
516
520
|
let thinkingLevelMap;
|
|
517
521
|
let compat;
|
|
@@ -542,7 +546,7 @@ export function toProviderModels(models) {
|
|
|
542
546
|
thinkingLevelMap,
|
|
543
547
|
input: m.vision ? ["text", "image"] : ["text"],
|
|
544
548
|
cost: m.cost ?? UNKNOWN_MODEL_COST,
|
|
545
|
-
contextWindow: m.
|
|
549
|
+
contextWindow: effectiveContextWindow(m, options.maxContextTokens),
|
|
546
550
|
maxTokens: m.maxTokens,
|
|
547
551
|
compat,
|
|
548
552
|
};
|
package/dist/config.d.ts
CHANGED
|
@@ -37,6 +37,11 @@ export interface ApiModel {
|
|
|
37
37
|
max_tokens: number;
|
|
38
38
|
/** Older gateways omit this field; missing means unknown coverage. */
|
|
39
39
|
free_package_eligible?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* 网关建议的自动压缩预算(token);缺失/null 时 CLI 用内置默认 200K。
|
|
42
|
+
* 用户设置 compaction.maxContextTokens 优先级更高(见 effectiveContextWindow)。
|
|
43
|
+
*/
|
|
44
|
+
compact_at_tokens?: number | null;
|
|
40
45
|
price: {
|
|
41
46
|
input: number;
|
|
42
47
|
output: number;
|
|
@@ -74,8 +79,23 @@ export interface ModelDef {
|
|
|
74
79
|
cost: ModelCost | null;
|
|
75
80
|
/** 网关下发的免费用量包覆盖标记;老网关缺失时为 undefined(不派生 note)。 */
|
|
76
81
|
freeEligible?: boolean;
|
|
82
|
+
/** 网关按模型下发的自动压缩预算(token);缺失时用 DEFAULT_COMPACTION_BUDGET_TOKENS。 */
|
|
83
|
+
compactAtTokens?: number;
|
|
77
84
|
note: string;
|
|
78
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* 自动压缩预算默认值(token)。pi 的自动压缩阈值 = 模型 contextWindow − reserveTokens,
|
|
88
|
+
* 而 deepseek-flash 的窗口是 1M,会话逼近 100 万 token 才压缩——每轮 2 MB 请求体对渠道、
|
|
89
|
+
* 时延、成本都是负担(近 7 天 >200K 的请求占 28% 却吃掉 54% 采购)。所以把注册给 pi 的
|
|
90
|
+
* contextWindow 钉在 min(模型窗口, 预算),压缩、/context 百分比、溢出判定都随之按预算算。
|
|
91
|
+
* 只影响自动压缩时机,不改模型能力。见 docs/dev-plan-long-session-auto-compact-2026-09-14.md。
|
|
92
|
+
*/
|
|
93
|
+
export declare const DEFAULT_COMPACTION_BUDGET_TOKENS = 200000;
|
|
94
|
+
/**
|
|
95
|
+
* 注册给 pi 的 contextWindow:优先级 用户设置 > 网关下发 > 默认 200K;预算为 0 表示关闭
|
|
96
|
+
* (沿用模型窗口)。设置值来自 readCompactionBudgetSetting(),undefined = 用户没设。
|
|
97
|
+
*/
|
|
98
|
+
export declare function effectiveContextWindow(m: Pick<ModelDef, "contextWindow" | "compactAtTokens">, maxContextTokensSetting: number | undefined): number;
|
|
79
99
|
export declare const MODELS: ModelDef[];
|
|
80
100
|
/** Replace MODELS with a fresh list fetched from server (e.g. at startup). */
|
|
81
101
|
export declare function setModelsFromApi(apiModels: ModelDef[]): void;
|
|
@@ -154,8 +174,23 @@ export interface AgentSettings {
|
|
|
154
174
|
autoUpdate?: boolean;
|
|
155
175
|
/** false 时关闭客户端事件上报(见 telemetry.ts;环境变量 U1S1_TELEMETRY=0 同效) */
|
|
156
176
|
telemetry?: boolean;
|
|
177
|
+
/** pi 自己的 compaction 设置块;u1s1 额外认 maxContextTokens(自动压缩预算,0 = 关) */
|
|
178
|
+
compaction?: {
|
|
179
|
+
enabled?: boolean;
|
|
180
|
+
reserveTokens?: number;
|
|
181
|
+
keepRecentTokens?: number;
|
|
182
|
+
maxContextTokens?: number;
|
|
183
|
+
[key: string]: unknown;
|
|
184
|
+
};
|
|
157
185
|
[key: string]: unknown;
|
|
158
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* 用户设置的自动压缩预算(settings.json → compaction.maxContextTokens)。
|
|
189
|
+
* 未设置/非法 → undefined(走下发值或默认);0 → 0(关闭,沿用模型窗口)。
|
|
190
|
+
*/
|
|
191
|
+
export declare function readCompactionBudgetSetting(settings?: AgentSettings): number | undefined;
|
|
192
|
+
/** pi 自动压缩的保留余量(settings.json → compaction.reserveTokens,pi 默认 16,384)。 */
|
|
193
|
+
export declare function readCompactionReserveTokens(settings?: AgentSettings): number;
|
|
159
194
|
/** Read u1s1 agent settings (settings.json). Returns empty object if missing or invalid. */
|
|
160
195
|
export declare function readSettings(): AgentSettings;
|
|
161
196
|
/** Model last chosen in-session via /model (pi writes this). */
|
package/dist/config.js
CHANGED
|
@@ -78,16 +78,40 @@ export function apiModelToDef(m) {
|
|
|
78
78
|
cacheWrite: 0,
|
|
79
79
|
},
|
|
80
80
|
freeEligible: typeof m.free_package_eligible === "boolean" ? m.free_package_eligible : undefined,
|
|
81
|
+
compactAtTokens: positiveInteger(m.compact_at_tokens),
|
|
81
82
|
note: "",
|
|
82
83
|
};
|
|
83
84
|
}
|
|
85
|
+
function positiveInteger(value) {
|
|
86
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : undefined;
|
|
87
|
+
}
|
|
84
88
|
/** pi 的 Model 类型要求 cost 非空;价格未知时按 0 交给 pi(与自有端点同一约定)。 */
|
|
85
89
|
export const UNKNOWN_MODEL_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
90
|
+
/**
|
|
91
|
+
* 自动压缩预算默认值(token)。pi 的自动压缩阈值 = 模型 contextWindow − reserveTokens,
|
|
92
|
+
* 而 deepseek-flash 的窗口是 1M,会话逼近 100 万 token 才压缩——每轮 2 MB 请求体对渠道、
|
|
93
|
+
* 时延、成本都是负担(近 7 天 >200K 的请求占 28% 却吃掉 54% 采购)。所以把注册给 pi 的
|
|
94
|
+
* contextWindow 钉在 min(模型窗口, 预算),压缩、/context 百分比、溢出判定都随之按预算算。
|
|
95
|
+
* 只影响自动压缩时机,不改模型能力。见 docs/dev-plan-long-session-auto-compact-2026-09-14.md。
|
|
96
|
+
*/
|
|
97
|
+
export const DEFAULT_COMPACTION_BUDGET_TOKENS = 200_000;
|
|
98
|
+
/**
|
|
99
|
+
* 注册给 pi 的 contextWindow:优先级 用户设置 > 网关下发 > 默认 200K;预算为 0 表示关闭
|
|
100
|
+
* (沿用模型窗口)。设置值来自 readCompactionBudgetSetting(),undefined = 用户没设。
|
|
101
|
+
*/
|
|
102
|
+
export function effectiveContextWindow(m, maxContextTokensSetting) {
|
|
103
|
+
const budget = maxContextTokensSetting ?? m.compactAtTokens ?? DEFAULT_COMPACTION_BUDGET_TOKENS;
|
|
104
|
+
if (!(budget > 0))
|
|
105
|
+
return m.contextWindow;
|
|
106
|
+
return Math.min(m.contextWindow, budget);
|
|
107
|
+
}
|
|
86
108
|
export const MODELS = [
|
|
87
109
|
{
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
110
|
+
// DeepSeek 官方 2026-09-10 起统一为 deepseek-flash(= DeepSeek-V4.1-Flash);
|
|
111
|
+
// 旧 id deepseek-v4-flash 等由网关按别名转到同一模型、同一价格(model-catalog.ts)
|
|
112
|
+
id: "deepseek-flash",
|
|
113
|
+
name: "DeepSeek Flash (u1s1)",
|
|
114
|
+
aliases: ["deepseek", "flash", "v4-flash", "v4.1-flash"],
|
|
91
115
|
reasoning: true,
|
|
92
116
|
thinking: {
|
|
93
117
|
levels: ["off", "low", "high", "max"],
|
|
@@ -96,11 +120,11 @@ export const MODELS = [
|
|
|
96
120
|
levelMap: { off: "none", low: "low", high: "high", max: "max" },
|
|
97
121
|
requestFormat: "deepseek",
|
|
98
122
|
},
|
|
99
|
-
vision:
|
|
123
|
+
vision: true,
|
|
100
124
|
contextWindow: 1_048_576,
|
|
101
125
|
maxTokens: 384_000,
|
|
102
126
|
cost: null,
|
|
103
|
-
note: "默认 ·
|
|
127
|
+
note: "默认 · 免费用量包额度内免费,日常写代码首选,支持看图",
|
|
104
128
|
},
|
|
105
129
|
{
|
|
106
130
|
id: "x-ai/grok-4.6",
|
|
@@ -229,6 +253,21 @@ function readJsonFile(path) {
|
|
|
229
253
|
return undefined;
|
|
230
254
|
}
|
|
231
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* 用户设置的自动压缩预算(settings.json → compaction.maxContextTokens)。
|
|
258
|
+
* 未设置/非法 → undefined(走下发值或默认);0 → 0(关闭,沿用模型窗口)。
|
|
259
|
+
*/
|
|
260
|
+
export function readCompactionBudgetSetting(settings = readSettings()) {
|
|
261
|
+
const raw = settings.compaction?.maxContextTokens;
|
|
262
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || raw < 0)
|
|
263
|
+
return undefined;
|
|
264
|
+
return Math.trunc(raw);
|
|
265
|
+
}
|
|
266
|
+
/** pi 自动压缩的保留余量(settings.json → compaction.reserveTokens,pi 默认 16,384)。 */
|
|
267
|
+
export function readCompactionReserveTokens(settings = readSettings()) {
|
|
268
|
+
const raw = settings.compaction?.reserveTokens;
|
|
269
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw >= 0 ? Math.trunc(raw) : 16_384;
|
|
270
|
+
}
|
|
232
271
|
/** Read u1s1 agent settings (settings.json). Returns empty object if missing or invalid. */
|
|
233
272
|
export function readSettings() {
|
|
234
273
|
return (readJsonFile(agentSettingsFile) ?? {});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ModelRef } from "./config.js";
|
|
2
|
+
/** pi 的 ContextUsage 子集(不直接依赖 pi 类型,便于单测)。 */
|
|
3
|
+
export interface ContextUsageLike {
|
|
4
|
+
tokens: number | null;
|
|
5
|
+
contextWindow: number;
|
|
6
|
+
percent: number | null;
|
|
7
|
+
}
|
|
8
|
+
export interface ContextEntryInput {
|
|
9
|
+
usage: ContextUsageLike | undefined;
|
|
10
|
+
model: ModelRef | undefined;
|
|
11
|
+
/** settings.json → compaction.maxContextTokens;undefined = 用户没设 */
|
|
12
|
+
budgetSetting: number | undefined;
|
|
13
|
+
reserveTokens: number;
|
|
14
|
+
}
|
|
15
|
+
/** 1_048_576 → "1M",200_000 → "200K",184_000 → "184K",12_345 → "12.3K"。 */
|
|
16
|
+
export declare function formatTokens(n: number): string;
|
|
17
|
+
/** /context 的输出行:占用、预算与模型窗口、触发点、怎么改。 */
|
|
18
|
+
export declare function contextEntryLines(input: ContextEntryInput): string[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { CUSTOM_ENDPOINTS, DEFAULT_COMPACTION_BUDGET_TOKENS, MODELS, PROVIDER_ID, } from "./config.js";
|
|
2
|
+
/** 1_048_576 → "1M",200_000 → "200K",184_000 → "184K",12_345 → "12.3K"。 */
|
|
3
|
+
export function formatTokens(n) {
|
|
4
|
+
if (n >= 1_000_000) {
|
|
5
|
+
const m = n / 1_000_000;
|
|
6
|
+
return `${m >= 10 ? Math.round(m) : Number(m.toFixed(1))}M`;
|
|
7
|
+
}
|
|
8
|
+
if (n >= 1_000) {
|
|
9
|
+
const k = n / 1_000;
|
|
10
|
+
return `${k >= 100 ? Math.round(k) : Number(k.toFixed(1))}K`;
|
|
11
|
+
}
|
|
12
|
+
return String(n);
|
|
13
|
+
}
|
|
14
|
+
function findModelDef(ref) {
|
|
15
|
+
if (!ref)
|
|
16
|
+
return undefined;
|
|
17
|
+
if (ref.provider === PROVIDER_ID)
|
|
18
|
+
return MODELS.find((m) => m.id === ref.id);
|
|
19
|
+
return CUSTOM_ENDPOINTS.find((e) => e.id === ref.provider)?.models.find((m) => m.id === ref.id);
|
|
20
|
+
}
|
|
21
|
+
/** /context 的输出行:占用、预算与模型窗口、触发点、怎么改。 */
|
|
22
|
+
export function contextEntryLines(input) {
|
|
23
|
+
const def = findModelDef(input.model);
|
|
24
|
+
const usage = input.usage;
|
|
25
|
+
if (!usage || usage.contextWindow <= 0) {
|
|
26
|
+
return ["当前模型没有上下文窗口信息,无法统计。"];
|
|
27
|
+
}
|
|
28
|
+
const budget = usage.contextWindow;
|
|
29
|
+
const modelWindow = def?.contextWindow ?? 0;
|
|
30
|
+
const lines = [];
|
|
31
|
+
if (usage.tokens === null || usage.percent === null) {
|
|
32
|
+
lines.push(`当前上下文:未知(刚压缩过,等下一次回复后才能统计) · 压缩预算 ${formatTokens(budget)}`);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
lines.push(`当前上下文:约 ${formatTokens(usage.tokens)} tokens,占压缩预算 ${formatTokens(budget)} 的 ${usage.percent.toFixed(1)}%`);
|
|
36
|
+
}
|
|
37
|
+
const trigger = Math.max(0, budget - input.reserveTokens);
|
|
38
|
+
const budgetOrigin = input.budgetSetting !== undefined
|
|
39
|
+
? "来自你的设置"
|
|
40
|
+
: def?.compactAtTokens
|
|
41
|
+
? "由 u1s1 按模型下发"
|
|
42
|
+
: `默认 ${formatTokens(DEFAULT_COMPACTION_BUDGET_TOKENS)}`;
|
|
43
|
+
const windowNote = modelWindow > budget ? `(模型窗口 ${formatTokens(modelWindow)},预算${budgetOrigin})` : `(${budgetOrigin})`;
|
|
44
|
+
lines.push(`超过约 ${formatTokens(trigger)} tokens 会自动压缩 ${windowNote};/compact 可随时手动压缩`);
|
|
45
|
+
lines.push("改预算:~/.u1s1/agent/settings.json 里 compaction.maxContextTokens(0 = 不限,按模型窗口);只影响自动压缩时机,不改模型能力");
|
|
46
|
+
return lines;
|
|
47
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { writeFileSync } from "node:fs";
|
|
|
4
4
|
import { cleanupBrandThemes, endpointKeyEnv, endpointProviderEntry, ensureBrandPrompt, ensureDefaultSettings, ensureProviderModels, ensureWorkflowPromptTemplate, scrubForeignProviderEnv, toProviderModels, writeAnnouncementsExtension, writeAttributionExtension, writeMcpExtension, writeCompactUiExtension, writeErrorHumanizeExtension, writeWebToolsExtension, } from "./agent-setup.js";
|
|
5
5
|
import { Text } from "@earendil-works/pi-tui";
|
|
6
6
|
import { printConsoleBanner } from "./brand.js";
|
|
7
|
-
import { agentDir, apiModelToDef, CUSTOM_ENDPOINTS, isPortableInstall, loadConfig, MODELS, persistPreferredModel, PROVIDER_ID, readSettings, refValid, resolvePreferredModel, setModelsFromApi, VERSION, } from "./config.js";
|
|
7
|
+
import { agentDir, apiModelToDef, CUSTOM_ENDPOINTS, isPortableInstall, loadConfig, MODELS, persistPreferredModel, PROVIDER_ID, readCompactionBudgetSetting, readCompactionReserveTokens, readSettings, refValid, resolvePreferredModel, setModelsFromApi, VERSION, } from "./config.js";
|
|
8
8
|
import { registerLoopCommand } from "./loop.js";
|
|
9
9
|
import { ensureSearchTools } from "./search-tools.js";
|
|
10
10
|
import { ensureUsableShell } from "./shell-doctor.js";
|
|
@@ -356,9 +356,9 @@ async function runAgent(cfg, args) {
|
|
|
356
356
|
theme.bold(theme.fg("text", "u1s1 常用操作")),
|
|
357
357
|
theme.fg("text", "直接打字说需求,回车发送 · Shift+Enter 换行 · Ctrl+V 贴图 · Esc 中断"),
|
|
358
358
|
theme.fg("text", "/model 切换模型(留意免费/价格提示) · /clear 清空上下文开新会话"),
|
|
359
|
-
theme.fg("text", "/usage 查剩余额度 · /
|
|
359
|
+
theme.fg("text", "/usage 查剩余额度 · /context 看上下文占用与压缩预算 · /resume 恢复历史会话"),
|
|
360
360
|
theme.fg("text", "/feedback 一句话反馈问题或建议(自动附带版本与请求编号建工单)"),
|
|
361
|
-
theme.fg("dim", "/compact
|
|
361
|
+
theme.fg("dim", "/compact 手动压缩上下文 · /settings 设置 · /hotkeys 全部快捷键 · /exit 退出"),
|
|
362
362
|
theme.fg("dim", "退出后在终端:u1s1 deploy 发布网页 · u1s1 update 升级"),
|
|
363
363
|
theme.fg("dim", "匿名使用统计只记会话开始/结束等节点,不含任何内容;U1S1_TELEMETRY=0 可关闭"),
|
|
364
364
|
theme.fg("dim", "新手教程 → https://u1s1.io/guides"),
|
|
@@ -385,6 +385,28 @@ async function runAgent(cfg, args) {
|
|
|
385
385
|
pi.appendEntry("u1s1-usage", await usageEntryData());
|
|
386
386
|
},
|
|
387
387
|
});
|
|
388
|
+
// /context:上下文占用与自动压缩预算。注册给 pi 的 contextWindow 是压缩预算
|
|
389
|
+
// (默认 200K,见 effectiveContextWindow),不是模型真实窗口,这里把两者都说清楚,
|
|
390
|
+
// 免得用户看着 1M 的模型却在 20 万 token 就被压缩时以为出了问题
|
|
391
|
+
pi.registerEntryRenderer("u1s1-context", (entry, _opts, theme) => {
|
|
392
|
+
const data = entry.data ?? {};
|
|
393
|
+
return new Text((data.lines ?? []).map((l) => theme.fg("text", l)).join("\n"), 1, 0);
|
|
394
|
+
});
|
|
395
|
+
pi.registerCommand("context", {
|
|
396
|
+
description: "查看上下文占用与自动压缩预算",
|
|
397
|
+
handler: async (_args, ctx) => {
|
|
398
|
+
const { contextEntryLines } = await import("./context-usage.js");
|
|
399
|
+
const settings = readSettings();
|
|
400
|
+
pi.appendEntry("u1s1-context", {
|
|
401
|
+
lines: contextEntryLines({
|
|
402
|
+
usage: ctx.getContextUsage(),
|
|
403
|
+
model: ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined,
|
|
404
|
+
budgetSetting: readCompactionBudgetSetting(settings),
|
|
405
|
+
reserveTokens: readCompactionReserveTokens(settings),
|
|
406
|
+
}),
|
|
407
|
+
});
|
|
408
|
+
},
|
|
409
|
+
});
|
|
388
410
|
// /feedback:会话内直接建工单,附版本/平台/最近请求编号(运营清单 E4)
|
|
389
411
|
pi.registerEntryRenderer("u1s1-feedback", (entry, _opts, theme) => {
|
|
390
412
|
const data = entry.data ?? {};
|
package/dist/subagent.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export declare function promptSubagentSession(session: PromptSession, task: stri
|
|
|
61
61
|
}): Promise<void>;
|
|
62
62
|
/**
|
|
63
63
|
* Spawn 一个独立上下文的子 agent 执行任务,返回其最终文本输出。
|
|
64
|
-
* 模型解析:"provider/id" 精确匹配;裸 id(如 deepseek-
|
|
64
|
+
* 模型解析:"provider/id" 精确匹配;裸 id(如 deepseek-flash)先按原样找,
|
|
65
65
|
* 再兜底到 u1s1 provider —— 和 CLI --model 的解析习惯保持一致。
|
|
66
66
|
* 失败(模型错误/超时/取消)抛错,由调用方决定容错语义。
|
|
67
67
|
*/
|
package/dist/subagent.js
CHANGED
|
@@ -106,7 +106,7 @@ function extractUsage(messages, model) {
|
|
|
106
106
|
}
|
|
107
107
|
/**
|
|
108
108
|
* Spawn 一个独立上下文的子 agent 执行任务,返回其最终文本输出。
|
|
109
|
-
* 模型解析:"provider/id" 精确匹配;裸 id(如 deepseek-
|
|
109
|
+
* 模型解析:"provider/id" 精确匹配;裸 id(如 deepseek-flash)先按原样找,
|
|
110
110
|
* 再兜底到 u1s1 provider —— 和 CLI --model 的解析习惯保持一致。
|
|
111
111
|
* 失败(模型错误/超时/取消)抛错,由调用方决定容错语义。
|
|
112
112
|
*/
|
package/dist/tools.js
CHANGED
|
@@ -582,7 +582,7 @@ export function createFetchTool(cfg) {
|
|
|
582
582
|
name: "web_fetch",
|
|
583
583
|
label: "读取网页",
|
|
584
584
|
description: "Fetch a URL and return its readable text content (HTML is stripped to text; JSON and plain text are returned as-is). Use it to read a page found via web_search, or any URL the user pasted. If the direct fetch fails or the page needs JavaScript, it automatically retries through a cloud headless browser. Long pages are returned in 30,000-character windows: when the result says it was truncated, call again with the same url and the offset it gives to read the next part.",
|
|
585
|
-
promptSnippet: "
|
|
585
|
+
promptSnippet: "Fetch a URL and convert it to readable text",
|
|
586
586
|
promptGuidelines: [
|
|
587
587
|
"Use web_fetch to read a specific URL, and web_search when you still need to find the URL.",
|
|
588
588
|
],
|
package/dist/usage.js
CHANGED
|
@@ -92,8 +92,8 @@ function packageUsageLines(me, tokensPerUsd) {
|
|
|
92
92
|
: `$${me.mtd_usd.toFixed(2)}`;
|
|
93
93
|
lines.push(` 本月已用 ${monthlyUsage}`);
|
|
94
94
|
lines.push("");
|
|
95
|
-
lines.push(" 免费用量包覆盖 DeepSeek
|
|
96
|
-
lines.push("
|
|
95
|
+
lines.push(" 免费用量包覆盖 DeepSeek Flash、GLM-5.3 Flash、Qwen3.8 Flash 和联网搜索。");
|
|
96
|
+
lines.push(" 其他模型不走免费包,可用余额或全模型包 → https://u1s1.io/dashboard");
|
|
97
97
|
lines.push(" Token 数按默认模型单价折算,为约数;用更贵的模型时消耗更快。");
|
|
98
98
|
lines.push("");
|
|
99
99
|
lines.push(...usageCtaLines(me));
|
|
@@ -107,7 +107,7 @@ function legacyUsageLines(me, tokensPerUsd) {
|
|
|
107
107
|
if (tokensPerUsd > 0) {
|
|
108
108
|
const tokens = (usd) => `${fmtTokensCn(usd * tokensPerUsd)} Token`;
|
|
109
109
|
lines.push(` 今日免费 还剩 ${fmtTokensCn(freeRemain * tokensPerUsd)} / ${tokens(freeTotal)} ${bar(freeRatio)}`);
|
|
110
|
-
lines.push(" DeepSeek
|
|
110
|
+
lines.push(" DeepSeek Flash · 北京时间 0 点恢复");
|
|
111
111
|
lines.push(` 永久余额 ${tokens(me.remaining_usd)}`);
|
|
112
112
|
lines.push(` 本月已用 约 ${tokens(me.mtd_usd)}($${me.mtd_usd.toFixed(2)})`);
|
|
113
113
|
lines.push("");
|
|
@@ -115,7 +115,7 @@ function legacyUsageLines(me, tokensPerUsd) {
|
|
|
115
115
|
}
|
|
116
116
|
else {
|
|
117
117
|
lines.push(` 今日免费 $${freeRemain.toFixed(2)} / $${freeTotal.toFixed(2)} ${bar(freeRatio)}`);
|
|
118
|
-
lines.push(" DeepSeek
|
|
118
|
+
lines.push(" DeepSeek Flash · 北京时间 0 点恢复");
|
|
119
119
|
lines.push(` 永久余额 $${me.remaining_usd.toFixed(2)}`);
|
|
120
120
|
lines.push(` 本月成本 $${me.mtd_usd.toFixed(2)}`);
|
|
121
121
|
}
|