longer-agent 0.1.1 → 0.1.3
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 +74 -178
- package/README.zh-CN.md +74 -178
- package/agent_templates/executor/agent.yaml +1 -0
- package/agent_templates/executor/system_prompt.md +1 -1
- package/agent_templates/explorer/agent.yaml +1 -0
- package/agent_templates/explorer/system_prompt.md +1 -1
- package/agent_templates/main/agent.yaml +1 -0
- package/agent_templates/main/system_prompt.md +3 -2
- package/dist/agents/tool-loop.d.ts.map +1 -1
- package/dist/agents/tool-loop.js +6 -0
- package/dist/agents/tool-loop.js.map +1 -1
- package/dist/auth/openai-oauth.d.ts.map +1 -1
- package/dist/auth/openai-oauth.js +6 -10
- package/dist/auth/openai-oauth.js.map +1 -1
- package/dist/cli.d.ts +1 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +81 -60
- package/dist/cli.js.map +1 -1
- package/dist/commands.d.ts +6 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +115 -27
- package/dist/commands.js.map +1 -1
- package/dist/config.d.ts +19 -26
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +80 -120
- package/dist/config.js.map +1 -1
- package/dist/dotenv.d.ts +18 -0
- package/dist/dotenv.d.ts.map +1 -0
- package/dist/dotenv.js +91 -0
- package/dist/dotenv.js.map +1 -0
- package/dist/home-path.d.ts +3 -0
- package/dist/home-path.d.ts.map +1 -0
- package/dist/home-path.js +7 -0
- package/dist/home-path.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/init-wizard.d.ts +2 -3
- package/dist/init-wizard.d.ts.map +1 -1
- package/dist/init-wizard.js +349 -145
- package/dist/init-wizard.js.map +1 -1
- package/dist/log-projection.d.ts.map +1 -1
- package/dist/log-projection.js +71 -12
- package/dist/log-projection.js.map +1 -1
- package/dist/managed-provider-credentials.d.ts +23 -0
- package/dist/managed-provider-credentials.d.ts.map +1 -0
- package/dist/managed-provider-credentials.js +56 -0
- package/dist/managed-provider-credentials.js.map +1 -0
- package/dist/mcp-client.d.ts.map +1 -1
- package/dist/mcp-client.js +2 -1
- package/dist/mcp-client.js.map +1 -1
- package/dist/mcp-config.d.ts +13 -0
- package/dist/mcp-config.d.ts.map +1 -0
- package/dist/mcp-config.js +64 -0
- package/dist/mcp-config.js.map +1 -0
- package/dist/model-discovery.d.ts +20 -0
- package/dist/model-discovery.d.ts.map +1 -0
- package/dist/model-discovery.js +47 -0
- package/dist/model-discovery.js.map +1 -0
- package/dist/model-selection.d.ts +1 -1
- package/dist/model-selection.d.ts.map +1 -1
- package/dist/model-selection.js +20 -10
- package/dist/model-selection.js.map +1 -1
- package/dist/persistence.d.ts +14 -1
- package/dist/persistence.d.ts.map +1 -1
- package/dist/persistence.js +12 -8
- package/dist/persistence.js.map +1 -1
- package/dist/provider-credential-flow.d.ts +28 -0
- package/dist/provider-credential-flow.d.ts.map +1 -0
- package/dist/provider-credential-flow.js +112 -0
- package/dist/provider-credential-flow.js.map +1 -0
- package/dist/provider-presets.d.ts +4 -0
- package/dist/provider-presets.d.ts.map +1 -1
- package/dist/provider-presets.js +26 -9
- package/dist/provider-presets.js.map +1 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +3 -2
- package/dist/providers/registry.js.map +1 -1
- package/dist/session.d.ts +6 -17
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +82 -216
- package/dist/session.js.map +1 -1
- package/dist/settings.d.ts +8 -27
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +4 -108
- package/dist/settings.js.map +1 -1
- package/dist/templates/loader.d.ts.map +1 -1
- package/dist/templates/loader.js +2 -0
- package/dist/templates/loader.js.map +1 -1
- package/dist/tools/basic.d.ts +2 -2
- package/dist/tools/basic.d.ts.map +1 -1
- package/dist/tools/basic.js +54 -7
- package/dist/tools/basic.js.map +1 -1
- package/dist/tools/comm.d.ts.map +1 -1
- package/dist/tools/comm.js +8 -7
- package/dist/tools/comm.js.map +1 -1
- package/dist/tui/app.d.ts.map +1 -1
- package/dist/tui/app.js +176 -39
- package/dist/tui/app.js.map +1 -1
- package/dist/tui/components/command-prompt-panel.d.ts +22 -0
- package/dist/tui/components/command-prompt-panel.d.ts.map +1 -0
- package/dist/tui/components/command-prompt-panel.js +26 -0
- package/dist/tui/components/command-prompt-panel.js.map +1 -0
- package/dist/tui/components/input-panel.d.ts.map +1 -1
- package/dist/tui/components/input-panel.js +8 -6
- package/dist/tui/components/input-panel.js.map +1 -1
- package/dist/tui/components/logo-panel.d.ts.map +1 -1
- package/dist/tui/components/logo-panel.js +2 -4
- package/dist/tui/components/logo-panel.js.map +1 -1
- package/dist/tui/components/plan-panel.d.ts +3 -1
- package/dist/tui/components/plan-panel.d.ts.map +1 -1
- package/dist/tui/components/plan-panel.js +15 -2
- package/dist/tui/components/plan-panel.js.map +1 -1
- package/dist/tui/components/status-bar.d.ts.map +1 -1
- package/dist/tui/components/status-bar.js +17 -4
- package/dist/tui/components/status-bar.js.map +1 -1
- package/dist/tui/status-bar-model-name.d.ts +2 -0
- package/dist/tui/status-bar-model-name.d.ts.map +1 -0
- package/dist/tui/status-bar-model-name.js +81 -0
- package/dist/tui/status-bar-model-name.js.map +1 -0
- package/dist/update-check.d.ts +19 -0
- package/dist/update-check.d.ts.map +1 -0
- package/dist/update-check.js +116 -0
- package/dist/update-check.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/package.json +9 -5
- package/prompts/tools/plan.md +11 -240
- package/prompts/tools/summarize_context.md +1 -1
- package/prompts/tools/time.md +6 -0
- package/configExample.yaml +0 -83
package/dist/session.js
CHANGED
|
@@ -16,7 +16,7 @@ import { Agent, isNoReply, NO_REPLY_MARKER } from "./agents/agent.js";
|
|
|
16
16
|
import { createEphemeralLogState } from "./ephemeral-log.js";
|
|
17
17
|
import { allocateContextId, stripContextTags, ContextTagStripBuffer } from "./context-rendering.js";
|
|
18
18
|
import { generateShowContext } from "./show-context.js";
|
|
19
|
-
import { getThinkingLevels
|
|
19
|
+
import { getThinkingLevels } from "./config.js";
|
|
20
20
|
import { ToolResult } from "./providers/base.js";
|
|
21
21
|
import { SPAWN_AGENT_TOOL, KILL_AGENT_TOOL, CHECK_STATUS_TOOL, WAIT_TOOL, SHOW_CONTEXT_TOOL, SUMMARIZE_CONTEXT_TOOL, ASK_TOOL, PLAN_TOOL, } from "./tools/comm.js";
|
|
22
22
|
import { buildBashEnv, executeTool, } from "./tools/basic.js";
|
|
@@ -30,7 +30,7 @@ import { LogIdAllocator, createSystemPrompt, createTurnStart, createUserMessage
|
|
|
30
30
|
import { projectToApiMessages } from "./log-projection.js";
|
|
31
31
|
import { archiveWindow, createGlobalTuiPreferences, createLogSessionMeta, } from "./persistence.js";
|
|
32
32
|
import { resolvePersistedModelSelection, } from "./model-selection.js";
|
|
33
|
-
import { DEFAULT_THRESHOLDS,
|
|
33
|
+
import { DEFAULT_THRESHOLDS, } from "./settings.js";
|
|
34
34
|
// ------------------------------------------------------------------
|
|
35
35
|
// Constants
|
|
36
36
|
// ------------------------------------------------------------------
|
|
@@ -43,13 +43,13 @@ const COMPACT_PROMPT_OUTPUT = `Distill this conversation into a continuation pro
|
|
|
43
43
|
|
|
44
44
|
**Before writing the continuation prompt**, update your important log with any key discoveries, decisions, or insights from this session that aren't already recorded there. The important log survives compaction and will be visible to the new instance — this is your last chance to persist valuable knowledge.
|
|
45
45
|
|
|
46
|
-
**What the new instance will already have:** your system prompt, the important log, AGENTS.md persistent memory, and the active plan
|
|
46
|
+
**What the new instance will already have:** your system prompt, the important log, AGENTS.md persistent memory, and the active plan (if any) are automatically re-injected after compact. Do not duplicate their contents in the continuation prompt — focus on what they don't cover: current progress, session-specific context, and in-flight work state. If you've discovered stable, long-term knowledge during this session, consider persisting it to the project AGENTS.md before compaction.
|
|
47
47
|
|
|
48
48
|
Your summary should capture everything that matters and nothing that doesn't. Use whatever structure best fits the actual content — there is no fixed template. But as you write, pressure-test yourself against these questions:
|
|
49
49
|
|
|
50
50
|
- **What are we trying to do?** The user's intent, goals, and any constraints or preferences they've expressed — stated or implied.
|
|
51
51
|
- **What do we know now that we didn't at the start?** Key discoveries, failed approaches, edge cases encountered, decisions made and *why*. (Skip anything already in your important log.)
|
|
52
|
-
- **Where exactly are we?** What's done, what's in progress, what's next. Be specific enough that work won't be repeated or skipped. (Skip anything already in your plan
|
|
52
|
+
- **Where exactly are we?** What's done, what's in progress, what's next. Be specific enough that work won't be repeated or skipped. (Skip anything already tracked in your plan.)
|
|
53
53
|
- **What artifacts exist?** Files read, created, or modified — with enough context about each to be actionable (not just a path list).
|
|
54
54
|
- **What tone/style/working relationship has been established?** If the user has shown preferences for how they like to collaborate, note them.
|
|
55
55
|
- **What explicit rules has the user stated?** Direct instructions about how to work, what not to do, approval requirements, or behavioral constraints the user has explicitly communicated (e.g., "don't modify code until I approve", "always run tests before committing"). Preserve these verbatim — they are binding rules, not suggestions.
|
|
@@ -64,14 +64,14 @@ You just made a tool call and received its result above. That result is real and
|
|
|
64
64
|
|
|
65
65
|
**Before writing the continuation prompt**, update your important log with any key discoveries, decisions, or insights from this session that aren't already recorded there. The important log survives compaction and will be visible to the new instance — this is your last chance to persist valuable knowledge.
|
|
66
66
|
|
|
67
|
-
**What the new instance will already have:** your system prompt, the important log, AGENTS.md persistent memory, and the active plan
|
|
67
|
+
**What the new instance will already have:** your system prompt, the important log, AGENTS.md persistent memory, and the active plan (if any) are automatically re-injected after compact. Do not duplicate their contents in the continuation prompt — focus on what they don't cover: current progress, session-specific context, and in-flight work state. If you've discovered stable, long-term knowledge during this session, consider persisting it to the project AGENTS.md before compaction.
|
|
68
68
|
|
|
69
69
|
Write in natural prose. Use structure where it aids clarity, not for its own sake. As you write, pressure-test yourself against these questions:
|
|
70
70
|
|
|
71
71
|
- **What are we trying to do?** The user's intent, goals, constraints, and preferences — stated or implied.
|
|
72
72
|
- **What do we know now that we didn't at the start?** Key discoveries, failed approaches, edge cases encountered, decisions made and why. (Skip anything already in your important log.)
|
|
73
73
|
- **Where exactly did we stop?** Be precise: what was the last tool call, what did it return, and what was supposed to happen next? The new instance must be able to pick up mid-step without repeating or skipping anything.
|
|
74
|
-
- **What's done, what's in progress, what remains?** Give a clear picture of overall progress, not just the interrupted step. (Skip anything already in your plan
|
|
74
|
+
- **What's done, what's in progress, what remains?** Give a clear picture of overall progress, not just the interrupted step. (Skip anything already tracked in your plan.)
|
|
75
75
|
- **What artifacts exist?** Files read, created, or modified — with enough context about each to be actionable.
|
|
76
76
|
- **What working style has the user shown?** Communication preferences, collaboration patterns, or explicit instructions about how they like to work.
|
|
77
77
|
- **What explicit rules has the user stated?** Direct instructions about how to work, what not to do, approval requirements, or behavioral constraints (e.g., "don't modify code until I approve", "always run tests before committing"). Preserve these verbatim — they are binding rules, not suggestions.
|
|
@@ -211,15 +211,14 @@ export class Session {
|
|
|
211
211
|
_thresholds = { ...DEFAULT_THRESHOLDS };
|
|
212
212
|
_hintResetNone = DEFAULT_THRESHOLDS.summarize_hint_level1 / 100 - 0.20;
|
|
213
213
|
_hintResetLevel1 = (DEFAULT_THRESHOLDS.summarize_hint_level1 + DEFAULT_THRESHOLDS.summarize_hint_level2) / 200;
|
|
214
|
-
//
|
|
215
|
-
|
|
214
|
+
// Context window multiplier (0.0–1.0). Effective context = contextLength × _contextRatio.
|
|
215
|
+
_contextRatio = 1.0;
|
|
216
216
|
// Hint compression (two-tier state machine)
|
|
217
217
|
_hintState = "none";
|
|
218
218
|
// show_context: number of remaining rounds where annotations are active
|
|
219
219
|
_showContextRoundsRemaining = 0;
|
|
220
220
|
_showContextAnnotations = null;
|
|
221
|
-
// Plan tracking
|
|
222
|
-
_activePlanFile = null;
|
|
221
|
+
// Plan tracking (inline-only, no plan file)
|
|
223
222
|
_activePlanCheckpoints = [];
|
|
224
223
|
_activePlanChecked = [];
|
|
225
224
|
// Skills
|
|
@@ -275,19 +274,18 @@ export class Session {
|
|
|
275
274
|
this._progress = opts.progress;
|
|
276
275
|
this._mcpManager = opts.mcpManager;
|
|
277
276
|
this._promptsDirs = opts.promptsDirs;
|
|
278
|
-
// Apply
|
|
279
|
-
if (opts.
|
|
280
|
-
this.
|
|
277
|
+
// Apply context ratio
|
|
278
|
+
if (opts.contextRatio !== undefined) {
|
|
279
|
+
this._contextRatio = Math.max(0.01, Math.min(1.0, opts.contextRatio));
|
|
281
280
|
}
|
|
282
281
|
// Attach store if provided (must be set before _initConversation)
|
|
283
282
|
if (opts.store) {
|
|
284
283
|
this._store = opts.store;
|
|
285
284
|
}
|
|
286
285
|
// Resolve path variables
|
|
287
|
-
|
|
288
|
-
this.
|
|
289
|
-
this.
|
|
290
|
-
this._systemData = pathOverrides.systemData ?? "";
|
|
286
|
+
this._projectRoot = process.cwd();
|
|
287
|
+
this._sessionArtifactsOverride = "";
|
|
288
|
+
this._systemData = "";
|
|
291
289
|
this._createdAt = new Date().toISOString();
|
|
292
290
|
this._initConversation();
|
|
293
291
|
this._toolExecutors = this._buildToolExecutors();
|
|
@@ -318,26 +316,10 @@ export class Session {
|
|
|
318
316
|
this._appendEntry(createSystemPrompt(this._nextLogId("system_prompt"), systemPrompt), false);
|
|
319
317
|
}
|
|
320
318
|
/**
|
|
321
|
-
*
|
|
319
|
+
* Effective context length for a given ModelConfig, scaled by context ratio.
|
|
322
320
|
*/
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const hysteresis = computeHysteresisThresholds(s.thresholds);
|
|
326
|
-
this._hintResetNone = hysteresis.hintResetNone / 100;
|
|
327
|
-
this._hintResetLevel1 = hysteresis.hintResetLevel1 / 100;
|
|
328
|
-
this._settingsMaxOutputTokens = s.maxOutputTokens;
|
|
329
|
-
// Apply to current primary agent's model config
|
|
330
|
-
this._applyMaxOutputTokensOverride(this.primaryAgent.modelConfig);
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* Effective maxTokens for a given ModelConfig, taking settings override into account.
|
|
334
|
-
* Clamps to [4096, modelMaxOutputTokens].
|
|
335
|
-
*/
|
|
336
|
-
_effectiveMaxTokens(mc) {
|
|
337
|
-
if (this._settingsMaxOutputTokens === undefined)
|
|
338
|
-
return mc.maxTokens;
|
|
339
|
-
const modelMax = getModelMaxOutputTokens(mc.model);
|
|
340
|
-
return Math.max(4096, Math.min(this._settingsMaxOutputTokens, modelMax ?? mc.maxTokens));
|
|
321
|
+
_effectiveContextLength(mc) {
|
|
322
|
+
return Math.round(mc.contextLength * this._contextRatio);
|
|
341
323
|
}
|
|
342
324
|
// ==================================================================
|
|
343
325
|
// Message infrastructure
|
|
@@ -760,7 +742,6 @@ export class Session {
|
|
|
760
742
|
this._shellCounter = 0;
|
|
761
743
|
this._showContextRoundsRemaining = 0;
|
|
762
744
|
this._showContextAnnotations = null;
|
|
763
|
-
this._activePlanFile = null;
|
|
764
745
|
this._activePlanCheckpoints = [];
|
|
765
746
|
this._activePlanChecked = [];
|
|
766
747
|
}
|
|
@@ -790,7 +771,6 @@ export class Session {
|
|
|
790
771
|
const restoredThinkingPreference = meta.thinkingLevel ?? "default";
|
|
791
772
|
const restoredCachePreference = meta.cacheHitEnabled ?? true;
|
|
792
773
|
this._resetTransientState();
|
|
793
|
-
this._applyMaxOutputTokensOverride(restoredModelConfig);
|
|
794
774
|
this.primaryAgent.replaceModelConfig(restoredModelConfig);
|
|
795
775
|
this._persistedModelSelection = this._buildPersistedModelSelection({
|
|
796
776
|
modelConfigName: restoredSelection.selectedConfigName,
|
|
@@ -828,19 +808,9 @@ export class Session {
|
|
|
828
808
|
// Restore ask state from log: find unclosed ask_request
|
|
829
809
|
this._restoreAskStateFromLog(entries);
|
|
830
810
|
// Restore active plan from meta
|
|
831
|
-
if (meta.
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
const { checkpoints, checked } = this._parsePlanCheckpoints(content);
|
|
835
|
-
if (checkpoints.length > 0) {
|
|
836
|
-
this._activePlanFile = meta.activePlanFile;
|
|
837
|
-
this._activePlanCheckpoints = checkpoints;
|
|
838
|
-
this._activePlanChecked = checked;
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
catch {
|
|
842
|
-
// Plan file no longer exists — skip restoration
|
|
843
|
-
}
|
|
811
|
+
if (meta.activePlanCheckpoints && meta.activePlanCheckpoints.length > 0) {
|
|
812
|
+
this._activePlanCheckpoints = meta.activePlanCheckpoints;
|
|
813
|
+
this._activePlanChecked = meta.activePlanChecked ?? meta.activePlanCheckpoints.map(() => false);
|
|
844
814
|
}
|
|
845
815
|
// Rebuild ask history from ask_resolution entries
|
|
846
816
|
this._askHistory = [];
|
|
@@ -877,7 +847,8 @@ export class Session {
|
|
|
877
847
|
thinkingLevel: this._thinkingLevel,
|
|
878
848
|
cacheHitEnabled: this._cacheHitEnabled,
|
|
879
849
|
summary: this._generateSummary(),
|
|
880
|
-
|
|
850
|
+
activePlanCheckpoints: this._activePlanCheckpoints.length > 0 ? this._activePlanCheckpoints : undefined,
|
|
851
|
+
activePlanChecked: this._activePlanChecked.length > 0 ? this._activePlanChecked : undefined,
|
|
881
852
|
}),
|
|
882
853
|
entries: this._log,
|
|
883
854
|
};
|
|
@@ -969,6 +940,12 @@ export class Session {
|
|
|
969
940
|
get skills() {
|
|
970
941
|
return this._skills;
|
|
971
942
|
}
|
|
943
|
+
get mcpManager() {
|
|
944
|
+
return this._mcpManager;
|
|
945
|
+
}
|
|
946
|
+
async ensureMcpReady() {
|
|
947
|
+
await this._ensureMcp();
|
|
948
|
+
}
|
|
972
949
|
/** Read-only access to disabled skill names. */
|
|
973
950
|
get disabledSkills() {
|
|
974
951
|
return this._disabledSkills;
|
|
@@ -1145,7 +1122,6 @@ export class Session {
|
|
|
1145
1122
|
*/
|
|
1146
1123
|
switchModel(modelConfigName) {
|
|
1147
1124
|
const newModelConfig = this.config.getModel(modelConfigName);
|
|
1148
|
-
this._applyMaxOutputTokensOverride(newModelConfig);
|
|
1149
1125
|
this.primaryAgent.replaceModelConfig(newModelConfig);
|
|
1150
1126
|
this._persistedModelSelection = this._buildPersistedModelSelection({
|
|
1151
1127
|
modelConfigName,
|
|
@@ -1156,16 +1132,6 @@ export class Session {
|
|
|
1156
1132
|
this._thinkingLevel = this._resolveThinkingLevelForModel(newModelConfig.model, this._preferredThinkingLevel);
|
|
1157
1133
|
this._cacheHitEnabled = this._preferredCacheHitEnabled;
|
|
1158
1134
|
}
|
|
1159
|
-
/**
|
|
1160
|
-
* If settings.json specifies max_output_tokens, clamp the ModelConfig.maxTokens
|
|
1161
|
-
* to [4096, modelMaxOutputTokens]. This mutates the ModelConfig in place.
|
|
1162
|
-
*/
|
|
1163
|
-
_applyMaxOutputTokensOverride(mc) {
|
|
1164
|
-
if (this._settingsMaxOutputTokens === undefined)
|
|
1165
|
-
return;
|
|
1166
|
-
const modelMax = getModelMaxOutputTokens(mc.model) ?? mc.maxTokens;
|
|
1167
|
-
mc.maxTokens = Math.max(4096, Math.min(this._settingsMaxOutputTokens, modelMax));
|
|
1168
|
-
}
|
|
1169
1135
|
applyGlobalPreferences(preferences) {
|
|
1170
1136
|
const prefs = createGlobalTuiPreferences(preferences);
|
|
1171
1137
|
this._preferredThinkingLevel = prefs.thinkingLevel;
|
|
@@ -1258,10 +1224,10 @@ export class Session {
|
|
|
1258
1224
|
_armShowContextAnnotations() {
|
|
1259
1225
|
const mc = this.primaryAgent.modelConfig;
|
|
1260
1226
|
const provider = this.primaryAgent._provider;
|
|
1261
|
-
const effectiveMax =
|
|
1227
|
+
const effectiveMax = mc.maxTokens;
|
|
1262
1228
|
const budget = provider.budgetCalcMode === "full_context"
|
|
1263
|
-
? mc
|
|
1264
|
-
: mc
|
|
1229
|
+
? this._effectiveContextLength(mc)
|
|
1230
|
+
: this._effectiveContextLength(mc) - effectiveMax;
|
|
1265
1231
|
const result = generateShowContext(this._log, this._lastInputTokens, budget);
|
|
1266
1232
|
this._showContextRoundsRemaining = 1;
|
|
1267
1233
|
this._showContextAnnotations = result.annotations;
|
|
@@ -2007,26 +1973,10 @@ export class Session {
|
|
|
2007
1973
|
? this._showContextAnnotations ?? undefined
|
|
2008
1974
|
: undefined;
|
|
2009
1975
|
let importantLog = this._readImportantLog();
|
|
2010
|
-
// Inject active plan
|
|
2011
|
-
if (this.
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
if (planContent) {
|
|
2015
|
-
importantLog += `\n\n---\n## Active Plan\n${planContent}`;
|
|
2016
|
-
// Detect checkpoint changes from file edits and emit update
|
|
2017
|
-
const { checkpoints, checked } = this._parsePlanCheckpoints(planContent);
|
|
2018
|
-
if (checkpoints.length !== this._activePlanCheckpoints.length ||
|
|
2019
|
-
checkpoints.some((t, i) => t !== this._activePlanCheckpoints[i]) ||
|
|
2020
|
-
checked.some((c, i) => c !== this._activePlanChecked[i])) {
|
|
2021
|
-
this._activePlanCheckpoints = checkpoints;
|
|
2022
|
-
this._activePlanChecked = checked;
|
|
2023
|
-
this._emitPlanProgress("plan_update");
|
|
2024
|
-
}
|
|
2025
|
-
}
|
|
2026
|
-
}
|
|
2027
|
-
catch {
|
|
2028
|
-
// Plan file may have been deleted externally — ignore
|
|
2029
|
-
}
|
|
1976
|
+
// Inject active plan alongside important log
|
|
1977
|
+
if (this._activePlanCheckpoints.length > 0) {
|
|
1978
|
+
const lines = this._activePlanCheckpoints.map((text, i) => `- [${this._activePlanChecked[i] ? "x" : " "}] ${text}`);
|
|
1979
|
+
importantLog += `\n\n---\n## Active Plan\n${lines.join("\n")}`;
|
|
2030
1980
|
}
|
|
2031
1981
|
const agentsMd = this._readAgentsMd();
|
|
2032
1982
|
return projectToApiMessages(this._log, {
|
|
@@ -2269,9 +2219,9 @@ export class Session {
|
|
|
2269
2219
|
}
|
|
2270
2220
|
const mc = this.primaryAgent.modelConfig;
|
|
2271
2221
|
const provider = this.primaryAgent._provider;
|
|
2272
|
-
const effectiveMax =
|
|
2222
|
+
const effectiveMax = mc.maxTokens;
|
|
2273
2223
|
const budget = provider.budgetCalcMode === "full_context"
|
|
2274
|
-
? mc
|
|
2224
|
+
? this._effectiveContextLength(mc) : this._effectiveContextLength(mc) - effectiveMax;
|
|
2275
2225
|
const result = generateShowContext(this._log, this._lastInputTokens, budget);
|
|
2276
2226
|
this._showContextRoundsRemaining = 1;
|
|
2277
2227
|
this._showContextAnnotations = result.annotations;
|
|
@@ -2346,149 +2296,68 @@ export class Session {
|
|
|
2346
2296
|
// ==================================================================
|
|
2347
2297
|
_execPlan(args) {
|
|
2348
2298
|
const action = args["action"];
|
|
2349
|
-
if (typeof action !== "string" || !["submit", "check", "
|
|
2350
|
-
return this._toolArgError("plan", "'action' must be one of: submit, check,
|
|
2299
|
+
if (typeof action !== "string" || !["submit", "check", "dismiss"].includes(action)) {
|
|
2300
|
+
return this._toolArgError("plan", "'action' must be one of: submit, check, dismiss.");
|
|
2351
2301
|
}
|
|
2352
2302
|
if (action === "submit") {
|
|
2353
|
-
const
|
|
2354
|
-
if (
|
|
2355
|
-
return
|
|
2356
|
-
const fileRel = fileArg.trim();
|
|
2357
|
-
const artifactsDir = this._resolveSessionArtifacts();
|
|
2358
|
-
let filePath;
|
|
2359
|
-
try {
|
|
2360
|
-
filePath = safePath({
|
|
2361
|
-
baseDir: artifactsDir,
|
|
2362
|
-
requestedPath: fileRel,
|
|
2363
|
-
cwd: artifactsDir,
|
|
2364
|
-
mustExist: true,
|
|
2365
|
-
expectFile: true,
|
|
2366
|
-
accessKind: "read",
|
|
2367
|
-
}).safePath;
|
|
2368
|
-
}
|
|
2369
|
-
catch (e) {
|
|
2370
|
-
if (e instanceof SafePathError) {
|
|
2371
|
-
if (e.code === "PATH_NOT_FOUND" || e.code === "PATH_NOT_FILE") {
|
|
2372
|
-
const candidatePath = e.details.resolvedPath || join(artifactsDir, fileRel);
|
|
2373
|
-
return new ToolResult({
|
|
2374
|
-
content: `Error: plan file not found at ${candidatePath}\n` +
|
|
2375
|
-
`The 'file' parameter is resolved relative to SESSION_ARTIFACTS (${artifactsDir}).\n` +
|
|
2376
|
-
`Make sure you wrote the plan file to this directory using write_file(path="${join(artifactsDir, fileRel)}").`,
|
|
2377
|
-
});
|
|
2378
|
-
}
|
|
2379
|
-
return new ToolResult({ content: `Error: invalid plan file path: ${e.message}` });
|
|
2380
|
-
}
|
|
2381
|
-
throw e;
|
|
2382
|
-
}
|
|
2383
|
-
let content;
|
|
2384
|
-
try {
|
|
2385
|
-
content = readFileSync(filePath, "utf-8");
|
|
2386
|
-
}
|
|
2387
|
-
catch (e) {
|
|
2388
|
-
return new ToolResult({
|
|
2389
|
-
content: `Error: could not read plan file: ${e instanceof Error ? e.message : String(e)}`,
|
|
2390
|
-
});
|
|
2303
|
+
const raw = args["checkpoints"];
|
|
2304
|
+
if (!Array.isArray(raw) || raw.length === 0) {
|
|
2305
|
+
return this._toolArgError("plan", "'checkpoints' must be a non-empty array of strings.");
|
|
2391
2306
|
}
|
|
2392
|
-
const
|
|
2307
|
+
const checkpoints = raw.map((c) => String(c).trim()).filter(Boolean);
|
|
2393
2308
|
if (checkpoints.length === 0) {
|
|
2394
|
-
return
|
|
2395
|
-
content: "Error: no checkpoints found in plan file. " +
|
|
2396
|
-
"Expected a '## Checkpoints' section with items like '- [ ] Do something'.",
|
|
2397
|
-
});
|
|
2309
|
+
return this._toolArgError("plan", "'checkpoints' items must not be empty.");
|
|
2398
2310
|
}
|
|
2399
|
-
this._activePlanFile = filePath;
|
|
2400
2311
|
this._activePlanCheckpoints = checkpoints;
|
|
2401
|
-
this._activePlanChecked =
|
|
2312
|
+
this._activePlanChecked = checkpoints.map(() => false);
|
|
2402
2313
|
this._emitPlanProgress("plan_submit");
|
|
2403
2314
|
return new ToolResult({
|
|
2404
2315
|
content: `Plan submitted with ${checkpoints.length} checkpoints.`,
|
|
2405
2316
|
});
|
|
2406
2317
|
}
|
|
2407
2318
|
if (action === "check") {
|
|
2408
|
-
if (
|
|
2319
|
+
if (this._activePlanCheckpoints.length === 0) {
|
|
2409
2320
|
return new ToolResult({ content: "Error: no active plan. Use action='submit' first." });
|
|
2410
2321
|
}
|
|
2411
2322
|
const item = args["item"];
|
|
2412
2323
|
if (typeof item !== "number" || !Number.isInteger(item)) {
|
|
2413
|
-
return this._toolArgError("plan", "'item' must be an integer index.");
|
|
2324
|
+
return this._toolArgError("plan", "'item' must be an integer index (1-based).");
|
|
2414
2325
|
}
|
|
2415
|
-
//
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
currentContent = readFileSync(this._activePlanFile, "utf-8");
|
|
2419
|
-
}
|
|
2420
|
-
catch {
|
|
2421
|
-
return new ToolResult({ content: "Error: could not read plan file." });
|
|
2422
|
-
}
|
|
2423
|
-
const { checkpoints, checked } = this._parsePlanCheckpoints(currentContent);
|
|
2424
|
-
if (checkpoints.length === 0) {
|
|
2425
|
-
return new ToolResult({ content: "Error: no checkpoints found in plan file." });
|
|
2426
|
-
}
|
|
2427
|
-
this._activePlanCheckpoints = checkpoints;
|
|
2428
|
-
this._activePlanChecked = checked;
|
|
2429
|
-
if (item < 0 || item >= checkpoints.length) {
|
|
2326
|
+
// Convert 1-based user index to 0-based internal index
|
|
2327
|
+
const idx = item - 1;
|
|
2328
|
+
if (idx < 0 || idx >= this._activePlanCheckpoints.length) {
|
|
2430
2329
|
return new ToolResult({
|
|
2431
|
-
content: `Error: 'item'
|
|
2330
|
+
content: `Error: 'item' ${item} is out of range (1..${this._activePlanCheckpoints.length}).`,
|
|
2432
2331
|
});
|
|
2433
2332
|
}
|
|
2434
|
-
this.
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
}
|
|
2452
|
-
checkpointIndex++;
|
|
2453
|
-
}
|
|
2454
|
-
}
|
|
2455
|
-
writeFileSync(this._activePlanFile, lines.join("\n"), "utf-8");
|
|
2456
|
-
}
|
|
2457
|
-
catch {
|
|
2458
|
-
// File write failure is non-fatal — in-memory state is still updated
|
|
2333
|
+
const checkpointText = this._activePlanCheckpoints[idx];
|
|
2334
|
+
this._activePlanChecked[idx] = true;
|
|
2335
|
+
// Check if all checkpoints are now complete → auto-finish
|
|
2336
|
+
const allDone = this._activePlanChecked.every(Boolean);
|
|
2337
|
+
if (allDone) {
|
|
2338
|
+
// Clear state immediately (so persistence sees no plan on interrupt)
|
|
2339
|
+
// but delay TUI panel dismissal so the user sees the all-checked state
|
|
2340
|
+
this._emitPlanProgress("plan_update");
|
|
2341
|
+
this._activePlanCheckpoints = [];
|
|
2342
|
+
this._activePlanChecked = [];
|
|
2343
|
+
setTimeout(() => {
|
|
2344
|
+
this._emitPlanProgress("plan_finish");
|
|
2345
|
+
}, 5000);
|
|
2346
|
+
return new ToolResult({
|
|
2347
|
+
content: `✓ Checkpoint ${item} done: ${checkpointText}\n` +
|
|
2348
|
+
`All checkpoints complete. Plan closed.`,
|
|
2349
|
+
});
|
|
2459
2350
|
}
|
|
2460
2351
|
this._emitPlanProgress("plan_update");
|
|
2461
2352
|
return new ToolResult({
|
|
2462
|
-
content:
|
|
2353
|
+
content: `✓ Checkpoint ${item} done: ${checkpointText}`,
|
|
2463
2354
|
});
|
|
2464
2355
|
}
|
|
2465
|
-
// action === "
|
|
2466
|
-
this._activePlanFile = null;
|
|
2356
|
+
// action === "dismiss"
|
|
2467
2357
|
this._activePlanCheckpoints = [];
|
|
2468
2358
|
this._activePlanChecked = [];
|
|
2469
2359
|
this._emitPlanProgress("plan_finish");
|
|
2470
|
-
return new ToolResult({ content: "Plan
|
|
2471
|
-
}
|
|
2472
|
-
_parsePlanCheckpoints(content) {
|
|
2473
|
-
const checkpoints = [];
|
|
2474
|
-
const checked = [];
|
|
2475
|
-
let inCheckpointsSection = false;
|
|
2476
|
-
for (const line of content.split("\n")) {
|
|
2477
|
-
if (/^## Checkpoints\b/.test(line)) {
|
|
2478
|
-
inCheckpointsSection = true;
|
|
2479
|
-
continue;
|
|
2480
|
-
}
|
|
2481
|
-
if (inCheckpointsSection && /^## /.test(line))
|
|
2482
|
-
break;
|
|
2483
|
-
if (inCheckpointsSection) {
|
|
2484
|
-
const match = line.match(/^- \[([x ])\] (.+)$/);
|
|
2485
|
-
if (match) {
|
|
2486
|
-
checkpoints.push(match[2]);
|
|
2487
|
-
checked.push(match[1] === "x");
|
|
2488
|
-
}
|
|
2489
|
-
}
|
|
2490
|
-
}
|
|
2491
|
-
return { checkpoints, checked };
|
|
2360
|
+
return new ToolResult({ content: "Plan dismissed." });
|
|
2492
2361
|
}
|
|
2493
2362
|
_emitPlanProgress(action) {
|
|
2494
2363
|
if (!this._progress)
|
|
@@ -2875,10 +2744,10 @@ export class Session {
|
|
|
2875
2744
|
return undefined;
|
|
2876
2745
|
const mc = this.primaryAgent.modelConfig;
|
|
2877
2746
|
const provider = this.primaryAgent._provider;
|
|
2878
|
-
const effectiveMax =
|
|
2747
|
+
const effectiveMax = mc.maxTokens;
|
|
2879
2748
|
const budget = provider.budgetCalcMode === "full_context"
|
|
2880
|
-
? mc
|
|
2881
|
-
: mc
|
|
2749
|
+
? this._effectiveContextLength(mc)
|
|
2750
|
+
: this._effectiveContextLength(mc) - effectiveMax;
|
|
2882
2751
|
if (budget <= 0)
|
|
2883
2752
|
return undefined;
|
|
2884
2753
|
const compactOutputRatio = this._thresholds.compact_output / 100;
|
|
@@ -2992,9 +2861,9 @@ export class Session {
|
|
|
2992
2861
|
return;
|
|
2993
2862
|
const mc = this.primaryAgent.modelConfig;
|
|
2994
2863
|
const provider = this.primaryAgent._provider;
|
|
2995
|
-
const effectiveMax =
|
|
2864
|
+
const effectiveMax = mc.maxTokens;
|
|
2996
2865
|
const budget = provider.budgetCalcMode === "full_context"
|
|
2997
|
-
? mc
|
|
2866
|
+
? this._effectiveContextLength(mc) : this._effectiveContextLength(mc) - effectiveMax;
|
|
2998
2867
|
if (budget <= 0)
|
|
2999
2868
|
return;
|
|
3000
2869
|
const ratio = this._lastInputTokens / budget;
|
|
@@ -3018,9 +2887,9 @@ export class Session {
|
|
|
3018
2887
|
_updateHintStateAfterApiCall() {
|
|
3019
2888
|
const mc = this.primaryAgent.modelConfig;
|
|
3020
2889
|
const provider = this.primaryAgent._provider;
|
|
3021
|
-
const effectiveMax =
|
|
2890
|
+
const effectiveMax = mc.maxTokens;
|
|
3022
2891
|
const budget = provider.budgetCalcMode === "full_context"
|
|
3023
|
-
? mc
|
|
2892
|
+
? this._effectiveContextLength(mc) : this._effectiveContextLength(mc) - effectiveMax;
|
|
3024
2893
|
if (budget <= 0)
|
|
3025
2894
|
return;
|
|
3026
2895
|
const ratio = this._lastInputTokens / budget;
|
|
@@ -3914,9 +3783,6 @@ export class Session {
|
|
|
3914
3783
|
"and conclusions.";
|
|
3915
3784
|
}
|
|
3916
3785
|
_getSubAgentModelConfig() {
|
|
3917
|
-
const name = this.config.subAgentModelName;
|
|
3918
|
-
if (name)
|
|
3919
|
-
return this.config.getModel(name);
|
|
3920
3786
|
return this.primaryAgent.modelConfig;
|
|
3921
3787
|
}
|
|
3922
3788
|
_buildSubAgentContext(includeImportantLog) {
|
|
@@ -4203,10 +4069,10 @@ export class Session {
|
|
|
4203
4069
|
_buildSubAgentCompactCheck(agent) {
|
|
4204
4070
|
const mc = agent.modelConfig;
|
|
4205
4071
|
const provider = agent._provider;
|
|
4206
|
-
const effectiveMax =
|
|
4072
|
+
const effectiveMax = mc.maxTokens;
|
|
4207
4073
|
const budget = provider.budgetCalcMode === "full_context"
|
|
4208
|
-
? mc
|
|
4209
|
-
: mc
|
|
4074
|
+
? this._effectiveContextLength(mc)
|
|
4075
|
+
: this._effectiveContextLength(mc) - effectiveMax;
|
|
4210
4076
|
if (budget <= 0)
|
|
4211
4077
|
return undefined;
|
|
4212
4078
|
const compactOutputRatio = this._thresholds.compact_output / 100;
|