@dimi-agent/cli 0.5.5 → 0.6.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/dist/main.mjs +270 -94
- package/package.json +4 -4
package/dist/main.mjs
CHANGED
|
@@ -121085,6 +121085,56 @@ var init_toolPolicyService = __esmMin((() => {
|
|
|
121085
121085
|
registerScopedService(2, IAgentToolPolicyService, AgentToolPolicyService, 0, "toolPolicy");
|
|
121086
121086
|
}));
|
|
121087
121087
|
//#endregion
|
|
121088
|
+
//#region ../../packages/agent-core-v2/src/agent/loop/contextSize.ts
|
|
121089
|
+
/**
|
|
121090
|
+
* Scale a token count by `percent` of the model's default window, keeping
|
|
121091
|
+
* at least `CONTEXT_SIZE_FLOOR_TOKENS` — but never more than the original
|
|
121092
|
+
* window, so models already below the floor (and `percent` at or above
|
|
121093
|
+
* 100, or unset) pass through unchanged.
|
|
121094
|
+
*/
|
|
121095
|
+
function scaleContextTokens(tokens, percent) {
|
|
121096
|
+
if (!Number.isFinite(tokens) || tokens <= 0) return tokens;
|
|
121097
|
+
if (percent === void 0 || percent <= 0 || percent >= 100) return tokens;
|
|
121098
|
+
const scaled = Math.floor(tokens * percent / 100);
|
|
121099
|
+
return Math.max(scaled, Math.min(tokens, CONTEXT_SIZE_FLOOR_TOKENS));
|
|
121100
|
+
}
|
|
121101
|
+
/**
|
|
121102
|
+
* Apply the configured context-size percentage to a model capability.
|
|
121103
|
+
* Returns the original object unchanged when nothing changes, so
|
|
121104
|
+
* `UNKNOWN_CAPABILITY` identity and other callers relying on object
|
|
121105
|
+
* equality keep working.
|
|
121106
|
+
*/
|
|
121107
|
+
function scaleModelCapabilityContext(capability, percent) {
|
|
121108
|
+
if (percent === void 0 || percent <= 0 || percent >= 100) return capability;
|
|
121109
|
+
const maxContextTokens = scaleContextTokens(capability.max_context_tokens, percent);
|
|
121110
|
+
const maxInputTokens = capability.max_input_tokens === void 0 ? void 0 : scaleContextTokens(capability.max_input_tokens, percent);
|
|
121111
|
+
if (maxContextTokens === capability.max_context_tokens && maxInputTokens === capability.max_input_tokens) return capability;
|
|
121112
|
+
return {
|
|
121113
|
+
...capability,
|
|
121114
|
+
max_context_tokens: maxContextTokens,
|
|
121115
|
+
max_input_tokens: maxInputTokens
|
|
121116
|
+
};
|
|
121117
|
+
}
|
|
121118
|
+
/**
|
|
121119
|
+
* Offered percentage levels for a model window: `100`, `95`, … descending
|
|
121120
|
+
* in `CONTEXT_SIZE_STEP_PERCENT` steps while the scaled size stays at or
|
|
121121
|
+
* above `CONTEXT_SIZE_FLOOR_TOKENS`. Empty when the window is below the
|
|
121122
|
+
* floor — the model's context size is not adjustable.
|
|
121123
|
+
*/
|
|
121124
|
+
function contextSizePercentOptions(contextWindow) {
|
|
121125
|
+
if (!Number.isFinite(contextWindow) || contextWindow <= 0) return [];
|
|
121126
|
+
const options = [];
|
|
121127
|
+
for (let percent = 100; percent >= 5; percent -= 5) {
|
|
121128
|
+
if (Math.floor(contextWindow * percent / 100) < 2e5) break;
|
|
121129
|
+
options.push(percent);
|
|
121130
|
+
}
|
|
121131
|
+
return options;
|
|
121132
|
+
}
|
|
121133
|
+
var CONTEXT_SIZE_FLOOR_TOKENS;
|
|
121134
|
+
var init_contextSize$1 = __esmMin((() => {
|
|
121135
|
+
CONTEXT_SIZE_FLOOR_TOKENS = 2e5;
|
|
121136
|
+
}));
|
|
121137
|
+
//#endregion
|
|
121088
121138
|
//#region ../../packages/agent-core-v2/src/agent/loop/configSection.ts
|
|
121089
121139
|
function parseNonNegativeInt(raw) {
|
|
121090
121140
|
const value = raw.trim();
|
|
@@ -121098,6 +121148,7 @@ var init_configSection$5 = __esmMin((() => {
|
|
|
121098
121148
|
init_config$5();
|
|
121099
121149
|
init_configSectionContributions();
|
|
121100
121150
|
init_toml();
|
|
121151
|
+
init_contextSize$1();
|
|
121101
121152
|
LOOP_CONTROL_SECTION = "loopControl";
|
|
121102
121153
|
LOOP_MAX_STEPS_PER_TURN_ENV = "DIMI_LOOP_MAX_STEPS_PER_TURN";
|
|
121103
121154
|
LOOP_MAX_RETRIES_PER_STEP_ENV = "DIMI_LOOP_MAX_RETRIES_PER_STEP";
|
|
@@ -121106,7 +121157,13 @@ var init_configSection$5 = __esmMin((() => {
|
|
|
121106
121157
|
maxRetriesPerStep: number$2().int().min(0).optional(),
|
|
121107
121158
|
maxRalphIterations: number$2().int().min(-1).optional(),
|
|
121108
121159
|
reservedContextSize: number$2().int().min(0).optional(),
|
|
121109
|
-
compactionTriggerRatio: number$2().min(.5).max(.99).optional()
|
|
121160
|
+
compactionTriggerRatio: number$2().min(.5).max(.99).optional(),
|
|
121161
|
+
/**
|
|
121162
|
+
* Effective context window as a percentage of the model's default, in
|
|
121163
|
+
* 5% steps, never below `CONTEXT_SIZE_FLOOR_TOKENS`. See
|
|
121164
|
+
* `agent/loop/contextSize.ts` for the scaling semantics.
|
|
121165
|
+
*/
|
|
121166
|
+
contextSizePercent: number$2().int().min(5).max(100).multipleOf(5).optional()
|
|
121110
121167
|
});
|
|
121111
121168
|
loopControlEnvBindings = envBindings(LoopControlSchema, {
|
|
121112
121169
|
maxStepsPerTurn: {
|
|
@@ -211855,6 +211912,8 @@ var init_profileService = __esmMin((() => {
|
|
|
211855
211912
|
init_errors$11();
|
|
211856
211913
|
init_bootstrap();
|
|
211857
211914
|
init_config$5();
|
|
211915
|
+
init_configSection$5();
|
|
211916
|
+
init_contextSize$1();
|
|
211858
211917
|
init_hostEnvironment();
|
|
211859
211918
|
init_hostFileSystem();
|
|
211860
211919
|
init_sessionContext();
|
|
@@ -211942,6 +212001,7 @@ var init_profileService = __esmMin((() => {
|
|
|
211942
212001
|
this.publishToolPatternWarnings();
|
|
211943
212002
|
this.refreshSystemPrompt();
|
|
211944
212003
|
}
|
|
212004
|
+
if (domain === "loopControl") this.emitStatusUpdated();
|
|
211945
212005
|
}));
|
|
211946
212006
|
this._register(this.skillCatalog.onDidChange((sourceId) => {
|
|
211947
212007
|
if (sourceId === "plugin") this.refreshSystemPrompt();
|
|
@@ -212139,7 +212199,7 @@ var init_profileService = __esmMin((() => {
|
|
|
212139
212199
|
return {
|
|
212140
212200
|
cwd: this.cwd,
|
|
212141
212201
|
modelAlias: this.modelAlias,
|
|
212142
|
-
modelCapabilities:
|
|
212202
|
+
modelCapabilities: this.capabilitiesFor(model),
|
|
212143
212203
|
profileName: this.profileName,
|
|
212144
212204
|
thinkingLevel: this.thinkingLevel,
|
|
212145
212205
|
systemPrompt: this.systemPrompt,
|
|
@@ -212154,10 +212214,10 @@ var init_profileService = __esmMin((() => {
|
|
|
212154
212214
|
resolveModelContext() {
|
|
212155
212215
|
const modelAlias = this.model;
|
|
212156
212216
|
const model = this.modelCatalog.get(modelAlias);
|
|
212157
|
-
const loopControl = this.config.get(
|
|
212217
|
+
const loopControl = this.config.get(LOOP_CONTROL_SECTION);
|
|
212158
212218
|
return {
|
|
212159
212219
|
modelAlias,
|
|
212160
|
-
modelCapabilities:
|
|
212220
|
+
modelCapabilities: this.capabilitiesFor(model),
|
|
212161
212221
|
maxOutputSize: model.maxTokens,
|
|
212162
212222
|
alwaysThinking: modelAlwaysThinking(model) || void 0,
|
|
212163
212223
|
thinkingLevel: this.resolveThinkingState(model).effective,
|
|
@@ -212182,8 +212242,15 @@ var init_profileService = __esmMin((() => {
|
|
|
212182
212242
|
};
|
|
212183
212243
|
}
|
|
212184
212244
|
getModelCapabilities() {
|
|
212185
|
-
|
|
212186
|
-
|
|
212245
|
+
return this.capabilitiesFor(this.tryResolveRawModel());
|
|
212246
|
+
}
|
|
212247
|
+
/**
|
|
212248
|
+
* Model capabilities with the user's `[loop_control] context_size_percent`
|
|
212249
|
+
* applied to the token limits. The percentage is read on every call, so
|
|
212250
|
+
* config changes take effect on the next request without a restart.
|
|
212251
|
+
*/
|
|
212252
|
+
capabilitiesFor(model) {
|
|
212253
|
+
return scaleModelCapabilityContext(model === void 0 ? UNKNOWN_CAPABILITY : modelCapabilities(model), this.config.get(LOOP_CONTROL_SECTION)?.contextSizePercent);
|
|
212187
212254
|
}
|
|
212188
212255
|
getMaxOutputSize() {
|
|
212189
212256
|
return this.tryResolveRawModel()?.maxTokens;
|
|
@@ -217678,6 +217745,7 @@ var init_src$6 = __esmMin((() => {
|
|
|
217678
217745
|
init_retry();
|
|
217679
217746
|
init_configSection$5();
|
|
217680
217747
|
init_configSection$5();
|
|
217748
|
+
init_contextSize$1();
|
|
217681
217749
|
init_loop();
|
|
217682
217750
|
init_loopService();
|
|
217683
217751
|
init_loopContinuation();
|
|
@@ -309726,6 +309794,134 @@ var init_busy_input_mode_selector = __esmMin((() => {
|
|
|
309726
309794
|
};
|
|
309727
309795
|
}));
|
|
309728
309796
|
//#endregion
|
|
309797
|
+
//#region src/utils/usage/usage-format.ts
|
|
309798
|
+
function usageNumber$1(value) {
|
|
309799
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
309800
|
+
}
|
|
309801
|
+
/**
|
|
309802
|
+
* Total prompt tokens for a single generation: non-cache input + cache
|
|
309803
|
+
* read + cache write/creation. Matches the denominator pi uses for CH%.
|
|
309804
|
+
*/
|
|
309805
|
+
function promptTokenTotal(usage) {
|
|
309806
|
+
if (usage === null || usage === void 0) return 0;
|
|
309807
|
+
return usageNumber$1(usage.inputOther) + usageNumber$1(usage.inputCacheRead) + usageNumber$1(usage.inputCacheCreation);
|
|
309808
|
+
}
|
|
309809
|
+
/**
|
|
309810
|
+
* Latest-step prompt-cache hit rate as a percentage in [0, 100].
|
|
309811
|
+
* Returns `undefined` when there is no prompt traffic, or when the
|
|
309812
|
+
* provider reported neither cache reads nor cache writes (no cache
|
|
309813
|
+
* signal — same gate as pi's footer `CH` badge).
|
|
309814
|
+
*/
|
|
309815
|
+
function cacheHitRatePercent(usage) {
|
|
309816
|
+
if (usage === null || usage === void 0) return void 0;
|
|
309817
|
+
const cacheRead = usageNumber$1(usage.inputCacheRead);
|
|
309818
|
+
const cacheWrite = usageNumber$1(usage.inputCacheCreation);
|
|
309819
|
+
if (cacheRead === 0 && cacheWrite === 0) return void 0;
|
|
309820
|
+
const prompt = promptTokenTotal(usage);
|
|
309821
|
+
if (prompt <= 0) return void 0;
|
|
309822
|
+
return Math.min(100, Math.max(0, cacheRead / prompt * 100));
|
|
309823
|
+
}
|
|
309824
|
+
/** Compact footer/report label, e.g. `CH85.0%`. */
|
|
309825
|
+
function formatCacheHitRate(rate) {
|
|
309826
|
+
if (!Number.isFinite(rate)) return "CH?%";
|
|
309827
|
+
return `CH${rate.toFixed(1)}%`;
|
|
309828
|
+
}
|
|
309829
|
+
/**
|
|
309830
|
+
* Format a token count in 1024-based units: context sizes are powers of
|
|
309831
|
+
* two, so 262144 reads as "256k", not "262.1k". k values at or above
|
|
309832
|
+
* 100 are rounded to whole numbers ("977k").
|
|
309833
|
+
*/
|
|
309834
|
+
function formatTokenCount(n) {
|
|
309835
|
+
if (!Number.isFinite(n) || n < 0) return "0";
|
|
309836
|
+
if (n >= 1024 * 1024) return `${trimDecimal(n / (1024 * 1024))}M`;
|
|
309837
|
+
if (n >= 1024) {
|
|
309838
|
+
const k = n / 1024;
|
|
309839
|
+
return `${k >= 100 ? Math.round(k) : trimDecimal(k)}k`;
|
|
309840
|
+
}
|
|
309841
|
+
return String(n);
|
|
309842
|
+
}
|
|
309843
|
+
/** One decimal place, dropping a redundant ".0" ("1.0" → "1", "1.5" stays). */
|
|
309844
|
+
function trimDecimal(v) {
|
|
309845
|
+
const s = v.toFixed(1);
|
|
309846
|
+
return s.endsWith(".0") ? s.slice(0, -2) : s;
|
|
309847
|
+
}
|
|
309848
|
+
/**
|
|
309849
|
+
* Format a token count in 1000-based units ("1M", "950k", "200k"). Unlike
|
|
309850
|
+
* `formatTokenCount` (1024-based, the footer/usage convention), this keeps
|
|
309851
|
+
* exact product numbers readable: the context-size picker's floor is a
|
|
309852
|
+
* literal 200k, and 5% steps of a 1M window land on round values.
|
|
309853
|
+
*/
|
|
309854
|
+
function formatDecimalTokenCount(n) {
|
|
309855
|
+
if (!Number.isFinite(n) || n < 0) return "0";
|
|
309856
|
+
if (n >= 1e6) return `${trimDecimal(n / 1e6)}M`;
|
|
309857
|
+
if (n >= 1e3) return `${trimDecimal(n / 1e3)}k`;
|
|
309858
|
+
return String(n);
|
|
309859
|
+
}
|
|
309860
|
+
/**
|
|
309861
|
+
* Usage as a whole-number percentage of `max`, ceiled so any non-zero
|
|
309862
|
+
* usage shows at least 1%, clamped to [0, 100]. A non-positive or
|
|
309863
|
+
* non-finite `max` reports 0.
|
|
309864
|
+
*/
|
|
309865
|
+
function usagePercent(used, max) {
|
|
309866
|
+
if (!Number.isFinite(max) || max <= 0) return 0;
|
|
309867
|
+
return Math.min(100, Math.max(0, Math.ceil(used / max * 100)));
|
|
309868
|
+
}
|
|
309869
|
+
/** `usagePercent` for callers that only know the ratio (NaN-safe). */
|
|
309870
|
+
function usagePercentFromRatio(ratio) {
|
|
309871
|
+
return Math.min(100, Math.max(0, Math.ceil(safeUsageRatio(ratio) * 100)));
|
|
309872
|
+
}
|
|
309873
|
+
/**
|
|
309874
|
+
* Build a `[███░░░░░░░]` style bar. Returns a plain-ASCII string with
|
|
309875
|
+
* `filled`/`empty` glyphs — colouring is the caller's responsibility.
|
|
309876
|
+
*/
|
|
309877
|
+
function renderProgressBar(ratio, width = 20, filled = "█", empty = "░") {
|
|
309878
|
+
const clamped = safeUsageRatio(ratio);
|
|
309879
|
+
const filledCount = Math.round(clamped * width);
|
|
309880
|
+
return filled.repeat(filledCount) + empty.repeat(Math.max(0, width - filledCount));
|
|
309881
|
+
}
|
|
309882
|
+
function safeUsageRatio(ratio) {
|
|
309883
|
+
return Number.isFinite(ratio) ? Math.max(0, Math.min(ratio, 1)) : 0;
|
|
309884
|
+
}
|
|
309885
|
+
/**
|
|
309886
|
+
* Map a usage ratio to a semantic colour token — the `/usage` renderer
|
|
309887
|
+
* translates these into palette hex values.
|
|
309888
|
+
*/
|
|
309889
|
+
function ratioSeverity(ratio) {
|
|
309890
|
+
if (ratio >= .85) return "danger";
|
|
309891
|
+
if (ratio >= .5) return "warn";
|
|
309892
|
+
return "ok";
|
|
309893
|
+
}
|
|
309894
|
+
var init_usage_format = __esmMin((() => {}));
|
|
309895
|
+
//#endregion
|
|
309896
|
+
//#region src/tui/components/dialogs/context-size-selector.ts
|
|
309897
|
+
function buildOptions(contextWindow, percentOptions) {
|
|
309898
|
+
return percentOptions.map((percent) => ({
|
|
309899
|
+
value: String(percent),
|
|
309900
|
+
label: percent === 100 ? "100% (default)" : `${percent}%`,
|
|
309901
|
+
description: `${formatDecimalTokenCount(Math.floor(contextWindow * percent / 100))} tokens`
|
|
309902
|
+
}));
|
|
309903
|
+
}
|
|
309904
|
+
var ContextSizeSelectorComponent;
|
|
309905
|
+
var init_context_size_selector = __esmMin((() => {
|
|
309906
|
+
init_src$6();
|
|
309907
|
+
init_usage_format();
|
|
309908
|
+
init_choice_picker();
|
|
309909
|
+
ContextSizeSelectorComponent = class extends ChoicePickerComponent {
|
|
309910
|
+
constructor(opts) {
|
|
309911
|
+
super({
|
|
309912
|
+
title: "Context size",
|
|
309913
|
+
hint: `Model window ${formatDecimalTokenCount(opts.contextWindow)} · floor ${formatDecimalTokenCount(CONTEXT_SIZE_FLOOR_TOKENS)}`,
|
|
309914
|
+
options: buildOptions(opts.contextWindow, opts.percentOptions),
|
|
309915
|
+
currentValue: String(opts.currentPercent),
|
|
309916
|
+
onSelect: (value) => {
|
|
309917
|
+
opts.onSelect(Number(value));
|
|
309918
|
+
},
|
|
309919
|
+
onCancel: opts.onCancel
|
|
309920
|
+
});
|
|
309921
|
+
}
|
|
309922
|
+
};
|
|
309923
|
+
}));
|
|
309924
|
+
//#endregion
|
|
309729
309925
|
//#region src/tui/components/dialogs/editor-selector.ts
|
|
309730
309926
|
var EDITOR_OPTIONS, EditorSelectorComponent;
|
|
309731
309927
|
var init_editor_selector = __esmMin((() => {
|
|
@@ -310186,7 +310382,7 @@ var init_permission_selector = __esmMin((() => {
|
|
|
310186
310382
|
//#endregion
|
|
310187
310383
|
//#region src/tui/components/dialogs/settings-selector.ts
|
|
310188
310384
|
function isSettingsSelection(value) {
|
|
310189
|
-
return value === "model" || value === "theme" || value === "editor" || value === "permission" || value === "busy-input" || value === "experiments" || value === "upgrade" || value === "usage";
|
|
310385
|
+
return value === "model" || value === "theme" || value === "editor" || value === "permission" || value === "busy-input" || value === "context-size" || value === "experiments" || value === "upgrade" || value === "usage";
|
|
310190
310386
|
}
|
|
310191
310387
|
var SETTINGS_OPTIONS, SettingsSelectorComponent;
|
|
310192
310388
|
var init_settings_selector = __esmMin((() => {
|
|
@@ -310217,6 +310413,11 @@ var init_settings_selector = __esmMin((() => {
|
|
|
310217
310413
|
label: "Busy input",
|
|
310218
310414
|
description: "Choose whether Enter queues or steers while the agent is working."
|
|
310219
310415
|
},
|
|
310416
|
+
{
|
|
310417
|
+
value: "context-size",
|
|
310418
|
+
label: "Context size",
|
|
310419
|
+
description: "Cap the conversation window as a percentage of the model default (min 200k)."
|
|
310420
|
+
},
|
|
310220
310421
|
{
|
|
310221
310422
|
value: "experiments",
|
|
310222
310423
|
label: "Experiments",
|
|
@@ -310462,93 +310663,6 @@ var init_mcp_status_panel = __esmMin((() => {
|
|
|
310462
310663
|
];
|
|
310463
310664
|
}));
|
|
310464
310665
|
//#endregion
|
|
310465
|
-
//#region src/utils/usage/usage-format.ts
|
|
310466
|
-
function usageNumber$1(value) {
|
|
310467
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
310468
|
-
}
|
|
310469
|
-
/**
|
|
310470
|
-
* Total prompt tokens for a single generation: non-cache input + cache
|
|
310471
|
-
* read + cache write/creation. Matches the denominator pi uses for CH%.
|
|
310472
|
-
*/
|
|
310473
|
-
function promptTokenTotal(usage) {
|
|
310474
|
-
if (usage === null || usage === void 0) return 0;
|
|
310475
|
-
return usageNumber$1(usage.inputOther) + usageNumber$1(usage.inputCacheRead) + usageNumber$1(usage.inputCacheCreation);
|
|
310476
|
-
}
|
|
310477
|
-
/**
|
|
310478
|
-
* Latest-step prompt-cache hit rate as a percentage in [0, 100].
|
|
310479
|
-
* Returns `undefined` when there is no prompt traffic, or when the
|
|
310480
|
-
* provider reported neither cache reads nor cache writes (no cache
|
|
310481
|
-
* signal — same gate as pi's footer `CH` badge).
|
|
310482
|
-
*/
|
|
310483
|
-
function cacheHitRatePercent(usage) {
|
|
310484
|
-
if (usage === null || usage === void 0) return void 0;
|
|
310485
|
-
const cacheRead = usageNumber$1(usage.inputCacheRead);
|
|
310486
|
-
const cacheWrite = usageNumber$1(usage.inputCacheCreation);
|
|
310487
|
-
if (cacheRead === 0 && cacheWrite === 0) return void 0;
|
|
310488
|
-
const prompt = promptTokenTotal(usage);
|
|
310489
|
-
if (prompt <= 0) return void 0;
|
|
310490
|
-
return Math.min(100, Math.max(0, cacheRead / prompt * 100));
|
|
310491
|
-
}
|
|
310492
|
-
/** Compact footer/report label, e.g. `CH85.0%`. */
|
|
310493
|
-
function formatCacheHitRate(rate) {
|
|
310494
|
-
if (!Number.isFinite(rate)) return "CH?%";
|
|
310495
|
-
return `CH${rate.toFixed(1)}%`;
|
|
310496
|
-
}
|
|
310497
|
-
/**
|
|
310498
|
-
* Format a token count in 1024-based units: context sizes are powers of
|
|
310499
|
-
* two, so 262144 reads as "256k", not "262.1k". k values at or above
|
|
310500
|
-
* 100 are rounded to whole numbers ("977k").
|
|
310501
|
-
*/
|
|
310502
|
-
function formatTokenCount(n) {
|
|
310503
|
-
if (!Number.isFinite(n) || n < 0) return "0";
|
|
310504
|
-
if (n >= 1024 * 1024) return `${trimDecimal(n / (1024 * 1024))}M`;
|
|
310505
|
-
if (n >= 1024) {
|
|
310506
|
-
const k = n / 1024;
|
|
310507
|
-
return `${k >= 100 ? Math.round(k) : trimDecimal(k)}k`;
|
|
310508
|
-
}
|
|
310509
|
-
return String(n);
|
|
310510
|
-
}
|
|
310511
|
-
/** One decimal place, dropping a redundant ".0" ("1.0" → "1", "1.5" stays). */
|
|
310512
|
-
function trimDecimal(v) {
|
|
310513
|
-
const s = v.toFixed(1);
|
|
310514
|
-
return s.endsWith(".0") ? s.slice(0, -2) : s;
|
|
310515
|
-
}
|
|
310516
|
-
/**
|
|
310517
|
-
* Usage as a whole-number percentage of `max`, ceiled so any non-zero
|
|
310518
|
-
* usage shows at least 1%, clamped to [0, 100]. A non-positive or
|
|
310519
|
-
* non-finite `max` reports 0.
|
|
310520
|
-
*/
|
|
310521
|
-
function usagePercent(used, max) {
|
|
310522
|
-
if (!Number.isFinite(max) || max <= 0) return 0;
|
|
310523
|
-
return Math.min(100, Math.max(0, Math.ceil(used / max * 100)));
|
|
310524
|
-
}
|
|
310525
|
-
/** `usagePercent` for callers that only know the ratio (NaN-safe). */
|
|
310526
|
-
function usagePercentFromRatio(ratio) {
|
|
310527
|
-
return Math.min(100, Math.max(0, Math.ceil(safeUsageRatio(ratio) * 100)));
|
|
310528
|
-
}
|
|
310529
|
-
/**
|
|
310530
|
-
* Build a `[███░░░░░░░]` style bar. Returns a plain-ASCII string with
|
|
310531
|
-
* `filled`/`empty` glyphs — colouring is the caller's responsibility.
|
|
310532
|
-
*/
|
|
310533
|
-
function renderProgressBar(ratio, width = 20, filled = "█", empty = "░") {
|
|
310534
|
-
const clamped = safeUsageRatio(ratio);
|
|
310535
|
-
const filledCount = Math.round(clamped * width);
|
|
310536
|
-
return filled.repeat(filledCount) + empty.repeat(Math.max(0, width - filledCount));
|
|
310537
|
-
}
|
|
310538
|
-
function safeUsageRatio(ratio) {
|
|
310539
|
-
return Number.isFinite(ratio) ? Math.max(0, Math.min(ratio, 1)) : 0;
|
|
310540
|
-
}
|
|
310541
|
-
/**
|
|
310542
|
-
* Map a usage ratio to a semantic colour token — the `/usage` renderer
|
|
310543
|
-
* translates these into palette hex values.
|
|
310544
|
-
*/
|
|
310545
|
-
function ratioSeverity(ratio) {
|
|
310546
|
-
if (ratio >= .85) return "danger";
|
|
310547
|
-
if (ratio >= .5) return "warn";
|
|
310548
|
-
return "ok";
|
|
310549
|
-
}
|
|
310550
|
-
var init_usage_format = __esmMin((() => {}));
|
|
310551
|
-
//#endregion
|
|
310552
310666
|
//#region src/tui/components/messages/usage-panel.ts
|
|
310553
310667
|
function usageRowLabel(row) {
|
|
310554
310668
|
const window = row.window;
|
|
@@ -312313,6 +312427,62 @@ function showBusyInputModePicker(host) {
|
|
|
312313
312427
|
}
|
|
312314
312428
|
}));
|
|
312315
312429
|
}
|
|
312430
|
+
/** `[loop_control]` from a `getConfig()` result (untyped domain access). */
|
|
312431
|
+
function loopControlFromConfig(config) {
|
|
312432
|
+
return config["loopControl"];
|
|
312433
|
+
}
|
|
312434
|
+
/** The active model's default context window in tokens, or 0 when unknown. */
|
|
312435
|
+
function activeModelContextWindow(host) {
|
|
312436
|
+
const alias = host.state.appState.model;
|
|
312437
|
+
return (alias === void 0 ? void 0 : host.state.appState.availableModels[alias])?.maxContextSize ?? 0;
|
|
312438
|
+
}
|
|
312439
|
+
/**
|
|
312440
|
+
* Open the context-size picker: 5% steps from the model's default window
|
|
312441
|
+
* (100%) down while the scaled window stays at or above 200k. Models whose
|
|
312442
|
+
* window is already below 200k are not adjustable — a notice explains why
|
|
312443
|
+
* instead of opening a one-option picker.
|
|
312444
|
+
*/
|
|
312445
|
+
function showContextSizePicker(host) {
|
|
312446
|
+
const contextWindow = activeModelContextWindow(host);
|
|
312447
|
+
if (contextWindow <= 0) {
|
|
312448
|
+
host.showNotice("Context size unavailable", "No model is active. Choose a model first.");
|
|
312449
|
+
return;
|
|
312450
|
+
}
|
|
312451
|
+
const percentOptions = contextSizePercentOptions(contextWindow);
|
|
312452
|
+
if (percentOptions.length <= 1) {
|
|
312453
|
+
host.showNotice("Context size cannot be adjusted", `This model's window (${formatDecimalTokenCount(contextWindow)}) is already at or below the ${formatDecimalTokenCount(CONTEXT_SIZE_FLOOR_TOKENS)} floor.`);
|
|
312454
|
+
return;
|
|
312455
|
+
}
|
|
312456
|
+
host.harness.getConfig().then((config) => {
|
|
312457
|
+
const currentPercent = loopControlFromConfig(config)?.contextSizePercent ?? 100;
|
|
312458
|
+
host.mountEditorReplacement(new ContextSizeSelectorComponent({
|
|
312459
|
+
contextWindow,
|
|
312460
|
+
percentOptions,
|
|
312461
|
+
currentPercent,
|
|
312462
|
+
onSelect: (percent) => {
|
|
312463
|
+
host.restoreEditor();
|
|
312464
|
+
applyContextSizeChoice(host, percent);
|
|
312465
|
+
},
|
|
312466
|
+
onCancel: () => {
|
|
312467
|
+
host.restoreEditor();
|
|
312468
|
+
}
|
|
312469
|
+
}));
|
|
312470
|
+
}, (error) => {
|
|
312471
|
+
host.showError(`Failed to load context size: ${formatErrorMessage$2(error)}`);
|
|
312472
|
+
});
|
|
312473
|
+
}
|
|
312474
|
+
async function applyContextSizeChoice(host, percent) {
|
|
312475
|
+
const contextWindow = activeModelContextWindow(host);
|
|
312476
|
+
try {
|
|
312477
|
+
await host.harness.setConfig({ loopControl: { contextSizePercent: percent } });
|
|
312478
|
+
} catch (error) {
|
|
312479
|
+
host.showError(`Failed to save context size: ${formatErrorMessage$2(error)}`);
|
|
312480
|
+
return;
|
|
312481
|
+
}
|
|
312482
|
+
const maxContextTokens = contextWindow > 0 ? scaleContextTokens(contextWindow, percent) : 0;
|
|
312483
|
+
if (maxContextTokens > 0) host.setAppState({ maxContextTokens });
|
|
312484
|
+
host.showNotice(`Context size: ${percent}%`, `Effective window ${formatDecimalTokenCount(maxContextTokens)} (default ${formatDecimalTokenCount(contextWindow)}).`);
|
|
312485
|
+
}
|
|
312316
312486
|
async function showExperimentsPanel(host) {
|
|
312317
312487
|
let features;
|
|
312318
312488
|
try {
|
|
@@ -312457,6 +312627,9 @@ function handleSettingsSelection(host, value) {
|
|
|
312457
312627
|
case "busy-input":
|
|
312458
312628
|
showBusyInputModePicker(host);
|
|
312459
312629
|
return;
|
|
312630
|
+
case "context-size":
|
|
312631
|
+
showContextSizePicker(host);
|
|
312632
|
+
return;
|
|
312460
312633
|
case "experiments":
|
|
312461
312634
|
showExperimentsPanel(host);
|
|
312462
312635
|
return;
|
|
@@ -312472,6 +312645,7 @@ var MODEL_PICKER_REFRESH_TIMEOUT_MS, MODEL_SWITCH_CACHE_WARNING, EFFORT_SWITCH_C
|
|
|
312472
312645
|
var init_config = __esmMin((() => {
|
|
312473
312646
|
init_src$4();
|
|
312474
312647
|
init_busy_input_mode_selector();
|
|
312648
|
+
init_context_size_selector();
|
|
312475
312649
|
init_editor_selector();
|
|
312476
312650
|
init_effort_selector();
|
|
312477
312651
|
init_experiments_selector();
|
|
@@ -312486,6 +312660,8 @@ var init_config = __esmMin((() => {
|
|
|
312486
312660
|
init_dimi_tui$1();
|
|
312487
312661
|
init_event_payload();
|
|
312488
312662
|
init_thinking_config();
|
|
312663
|
+
init_src$6();
|
|
312664
|
+
init_usage_format();
|
|
312489
312665
|
init_info();
|
|
312490
312666
|
init_experimental_flags();
|
|
312491
312667
|
MODEL_PICKER_REFRESH_TIMEOUT_MS = 2e3;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dimi-agent/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "The Starting Point for Next-Gen Agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -60,14 +60,14 @@
|
|
|
60
60
|
"tsx": "^4.21.0",
|
|
61
61
|
"yazl": "^3.3.1",
|
|
62
62
|
"zod": "^4.3.6",
|
|
63
|
+
"@dimi-agent/agent-core-v2": "^0.1.0",
|
|
63
64
|
"@dimi-agent/dimi-oauth": "^0.1.0",
|
|
64
65
|
"@dimi-agent/dimi-sdk": "^0.2.0",
|
|
65
66
|
"@dimi-agent/dimi-telemetry": "^0.1.0",
|
|
66
|
-
"@dimi-agent/agent-core-v2": "^0.1.0",
|
|
67
67
|
"@dimi-agent/dimi-web": "^0.1.0",
|
|
68
|
-
"@dimi-agent/
|
|
68
|
+
"@dimi-agent/kap-server": "^0.1.0",
|
|
69
69
|
"@dimi-agent/remote": "^0.1.0",
|
|
70
|
-
"@dimi-agent/
|
|
70
|
+
"@dimi-agent/pi-tui": "^0.1.0"
|
|
71
71
|
},
|
|
72
72
|
"optionalDependencies": {
|
|
73
73
|
"@mariozechner/clipboard": "^0.3.9",
|