@gajae-code/coding-agent 0.3.1 → 0.3.2

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -1
  3. package/dist/types/cli/args.d.ts +2 -0
  4. package/dist/types/commands/launch.d.ts +6 -0
  5. package/dist/types/config/model-profile-activation.d.ts +30 -0
  6. package/dist/types/config/model-profiles.d.ts +19 -0
  7. package/dist/types/config/model-registry.d.ts +8 -0
  8. package/dist/types/config/model-resolver.d.ts +1 -1
  9. package/dist/types/config/models-config-schema.d.ts +47 -0
  10. package/dist/types/config/settings-schema.d.ts +10 -0
  11. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +2 -1
  12. package/dist/types/main.d.ts +10 -1
  13. package/dist/types/modes/components/custom-provider-wizard.d.ts +10 -0
  14. package/dist/types/modes/components/model-selector.d.ts +6 -1
  15. package/dist/types/modes/components/provider-onboarding-selector.d.ts +1 -1
  16. package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
  17. package/dist/types/modes/types.d.ts +1 -0
  18. package/dist/types/sdk.d.ts +1 -1
  19. package/dist/types/task/executor.d.ts +1 -0
  20. package/dist/types/tools/hindsight-recall.d.ts +0 -2
  21. package/dist/types/tools/hindsight-reflect.d.ts +0 -2
  22. package/dist/types/tools/hindsight-retain.d.ts +0 -2
  23. package/dist/types/tools/index.d.ts +4 -4
  24. package/package.json +7 -7
  25. package/src/cli/args.ts +10 -0
  26. package/src/commands/launch.ts +8 -0
  27. package/src/config/model-profile-activation.ts +157 -0
  28. package/src/config/model-profiles.ts +155 -0
  29. package/src/config/model-registry.ts +19 -0
  30. package/src/config/model-resolver.ts +3 -2
  31. package/src/config/models-config-schema.ts +36 -0
  32. package/src/config/settings-schema.ts +10 -0
  33. package/src/defaults/gjc/skills/ultragoal/SKILL.md +11 -1
  34. package/src/defaults/gjc/skills/ultragoal/ai-slop-cleaner.md +61 -0
  35. package/src/defaults/gjc-defaults.ts +7 -0
  36. package/src/gjc-runtime/ultragoal-runtime.ts +119 -14
  37. package/src/internal-urls/docs-index.generated.ts +6 -9
  38. package/src/main.ts +67 -1
  39. package/src/modes/components/custom-provider-wizard.ts +318 -0
  40. package/src/modes/components/model-selector.ts +108 -18
  41. package/src/modes/components/provider-onboarding-selector.ts +6 -1
  42. package/src/modes/controllers/selector-controller.ts +57 -1
  43. package/src/modes/types.ts +1 -0
  44. package/src/prompts/memories/consolidation.md +1 -1
  45. package/src/prompts/memories/read-path.md +6 -7
  46. package/src/prompts/memories/unavailable.md +2 -2
  47. package/src/prompts/tools/bash.md +1 -1
  48. package/src/prompts/tools/irc.md +1 -1
  49. package/src/prompts/tools/read.md +2 -2
  50. package/src/prompts/tools/recall.md +1 -0
  51. package/src/prompts/tools/reflect.md +1 -0
  52. package/src/prompts/tools/retain.md +1 -0
  53. package/src/sdk.ts +1 -1
  54. package/src/slash-commands/builtin-registry.ts +1 -1
  55. package/src/task/executor.ts +2 -0
  56. package/src/task/index.ts +2 -0
  57. package/src/tools/hindsight-recall.ts +0 -2
  58. package/src/tools/hindsight-reflect.ts +0 -2
  59. package/src/tools/hindsight-retain.ts +0 -2
  60. package/src/tools/index.ts +4 -18
  61. package/src/tools/read.ts +3 -3
@@ -4,7 +4,7 @@ import { matchesSelectCancel } from "../../modes/utils/keybinding-matchers";
4
4
  import { formatModelOnboardingGuidance } from "../../setup/model-onboarding-guidance";
5
5
  import { DynamicBorder } from "./dynamic-border";
6
6
 
7
- export type ProviderOnboardingAction = "oauth-login" | "api-guide";
7
+ export type ProviderOnboardingAction = "custom-provider-wizard" | "oauth-login" | "api-guide";
8
8
 
9
9
  interface ProviderOnboardingOption {
10
10
  label: string;
@@ -13,6 +13,11 @@ interface ProviderOnboardingOption {
13
13
  }
14
14
 
15
15
  const PROVIDER_ONBOARDING_OPTIONS: ProviderOnboardingOption[] = [
16
+ {
17
+ label: "Add custom provider",
18
+ description: "Configure an OpenAI- or Anthropic-compatible API provider interactively.",
19
+ action: "custom-provider-wizard",
20
+ },
16
21
  {
17
22
  label: "Login with OAuth/subscription",
18
23
  description: "Open the interactive OAuth provider selector.",
@@ -4,6 +4,7 @@ import type { OAuthProvider } from "@gajae-code/ai/utils/oauth/types";
4
4
  import type { Component, OverlayHandle } from "@gajae-code/tui";
5
5
  import { Input, Loader, Spacer, Text } from "@gajae-code/tui";
6
6
  import { getAgentDbPath, getProjectDir } from "@gajae-code/utils";
7
+ import { activateModelProfile } from "../../config/model-profile-activation";
7
8
  import { settings } from "../../config/settings";
8
9
  import { DebugSelectorComponent } from "../../debug";
9
10
  import { disableProvider, enableProvider } from "../../discovery";
@@ -35,10 +36,12 @@ import {
35
36
  MODEL_ONBOARDING_PROVIDER_PRESET_COMMAND,
36
37
  MODEL_ONBOARDING_SETUP_COMMAND,
37
38
  } from "../../setup/model-onboarding-guidance";
39
+ import { addApiCompatibleProvider, formatProviderSetupResult } from "../../setup/provider-onboarding";
38
40
  import { isSearchProviderPreference, setPreferredImageProvider, setPreferredSearchProvider } from "../../tools";
39
41
  import { setSessionTerminalTitle } from "../../utils/title-generator";
40
42
  import { AgentDashboard } from "../components/agent-dashboard";
41
43
  import { AssistantMessageComponent } from "../components/assistant-message";
44
+ import { CustomProviderWizardComponent, type CustomProviderWizardSubmit } from "../components/custom-provider-wizard";
42
45
  import { ExtensionDashboard } from "../components/extensions";
43
46
  import { HistorySearchComponent } from "../components/history-search";
44
47
  import { JobsOverlayComponent } from "../components/jobs-overlay";
@@ -119,7 +122,9 @@ export class SelectorController {
119
122
  const selector = new ProviderOnboardingSelectorComponent(
120
123
  (action: ProviderOnboardingAction) => {
121
124
  done();
122
- if (action === "oauth-login") {
125
+ if (action === "custom-provider-wizard") {
126
+ this.showCustomProviderWizard();
127
+ } else if (action === "oauth-login") {
123
128
  void this.showOAuthSelector("login");
124
129
  } else {
125
130
  this.ctx.showStatus(formatProviderOnboardingCommandGuide());
@@ -134,6 +139,36 @@ export class SelectorController {
134
139
  });
135
140
  }
136
141
 
142
+ showCustomProviderWizard(): void {
143
+ this.showSelector(done => {
144
+ let wizard: CustomProviderWizardComponent;
145
+ const submit = async (input: CustomProviderWizardSubmit): Promise<void> => {
146
+ try {
147
+ const result = await addApiCompatibleProvider(input);
148
+ await this.ctx.session.modelRegistry.refresh("offline");
149
+ await this.ctx.notifyConfigChanged?.();
150
+ this.ctx.showStatus(formatProviderSetupResult(result));
151
+ done();
152
+ this.ctx.ui.requestRender();
153
+ } catch (err) {
154
+ const message = err instanceof Error ? err.message : String(err);
155
+ wizard.setSubmitError(`Provider setup failed: ${message}`);
156
+ }
157
+ };
158
+ wizard = new CustomProviderWizardComponent(
159
+ input => {
160
+ void submit(input);
161
+ },
162
+ () => {
163
+ done();
164
+ this.ctx.ui.requestRender();
165
+ },
166
+ () => this.ctx.ui.requestRender(),
167
+ );
168
+ return { component: wizard, focus: wizard };
169
+ });
170
+ }
171
+
137
172
  showSettingsSelector(): void {
138
173
  getAvailableThemes().then(availableThemes => {
139
174
  this.showSelector(done => {
@@ -502,6 +537,27 @@ export class SelectorController {
502
537
  this.ctx.ui.requestRender();
503
538
  return;
504
539
  }
540
+ if (selection.kind === "profile") {
541
+ await activateModelProfile(
542
+ {
543
+ session: this.ctx.session,
544
+ modelRegistry: this.ctx.session.modelRegistry,
545
+ settings: this.ctx.settings,
546
+ profileName: selection.profileName,
547
+ },
548
+ { persistDefault: selection.setDefault },
549
+ );
550
+ this.ctx.statusLine.invalidate();
551
+ this.ctx.updateEditorBorderColor();
552
+ this.ctx.showStatus(
553
+ selection.setDefault
554
+ ? `Default model profile: ${selection.profileName}`
555
+ : `Model profile: ${selection.profileName}`,
556
+ );
557
+ done();
558
+ this.ctx.ui.requestRender();
559
+ return;
560
+ }
505
561
  const { model, role, thinkingLevel, selector } = selection;
506
562
  if (role === null) {
507
563
  // Temporary: update agent state but don't persist to settings
@@ -147,6 +147,7 @@ export interface InteractiveModeContext {
147
147
  showStatus(message: string, options?: { dim?: boolean }): void;
148
148
  showError(message: string): void;
149
149
  showWarning(message: string): void;
150
+ notifyConfigChanged?: () => Promise<void> | void;
150
151
  showNewVersionNotification(newVersion: string): void;
151
152
  clearEditor(): void;
152
153
  updatePendingMessagesDisplay(): void;
@@ -1,5 +1,5 @@
1
1
  Memory consolidation agent.
2
- Memory root: memory://root
2
+ Memory backend: local private runtime state
3
3
  Input corpus (raw memories):
4
4
  {{raw_memories}}
5
5
  Input corpus (rollout summaries):
@@ -1,11 +1,10 @@
1
1
  # Memory Guidance
2
- Memory root: memory://root
2
+ Memory backend: local private runtime state
3
3
  Operational rules:
4
- 1) Read `memory://root/memory_summary.md` first.
5
- 2) If needed, inspect `memory://root/MEMORY.md` and `memory://root/skills/<name>/SKILL.md`.
6
- 3) Trust memory for heuristics and process context. Trust current repo files, runtime output, and user instruction for factual state and final decisions.
7
- 4) When memory changes your plan, cite the artifact path (e.g. `memory://root/skills/<name>/SKILL.md`) and pair it with current-repo evidence.
8
- 5) If memory disagrees with repo state or user instruction, prefer repo/user. Treat memory as stale. Proceed with corrected behavior, then update/regenerate memory artifacts.
9
- 6) Escalate confidence only after repository verification. Memory alone is NEVER sufficient proof.
4
+ 1) The memory summary below is already injected; do not try to call or invent a `memory` tool.
5
+ 2) Treat memory as heuristic process context. Trust current repo files, runtime output, and user instruction for factual state and final decisions.
6
+ 3) When memory changes your plan, pair it with current-repo evidence before acting.
7
+ 4) If memory disagrees with repo state or user instruction, prefer repo/user. Treat memory as stale. Proceed with corrected behavior, then update/regenerate memory artifacts through supported memory commands when available.
8
+ 5) Escalate confidence only after repository verification. Memory alone is NEVER sufficient proof.
10
9
  Memory summary:
11
10
  {{memory_summary}}
@@ -1,9 +1,9 @@
1
1
  # Memory Guidance
2
- Memory root: memory://root
2
+ Memory backend: local private runtime state
3
3
  Status: local memory is enabled, but no confirmed memory payload is available for this project yet.
4
4
 
5
5
  Operational rules:
6
6
  1) Do not claim that a user preference, fact, or instruction has been saved, remembered, or persisted unless a backend operation or a non-empty memory payload confirms it.
7
7
  2) If the user asks you to save or remember something now, explain that durable memory is not confirmed because local memory has no available payload/readback yet. You may use the instruction for the current session only.
8
- 3) If reading `memory://root` or `memory://root/memory_summary.md` fails, treat that as no confirmed memory, not as successful persistence.
8
+ 3) Do not try to call or invent a `memory` tool; local memory readback is unavailable in this session.
9
9
  4) The local backend consolidates prior session rollouts asynchronously; an empty payload is a degraded/unconfirmed state, not a successful save.
@@ -6,7 +6,7 @@ Executes bash command in shell session for terminal operations like git, bun, ca
6
6
  - Quote variable expansions like `"$NAME"` to preserve exact content
7
7
  - PTY mode is opt-in: set `pty: true` only when the command needs a real terminal (e.g. `sudo`, `ssh` requiring user input); default is `false`
8
8
  - Use `;` only when later commands should run regardless of earlier failures
9
- - Internal URIs (`agent://`, `artifact://`, `memory://`, `rule://`, `local://`) are auto-resolved to filesystem paths
9
+ - Internal URIs (`agent://`, `artifact://`, `rule://`, `local://`) are auto-resolved to filesystem paths
10
10
  {{#if asyncEnabled}}
11
11
  - Use `async: true` for long-running commands when you don't need immediate output; the call returns a background job ID and the result is delivered automatically as a follow-up.
12
12
  {{/if}}
@@ -24,7 +24,7 @@ These rules apply to both sending and replying.
24
24
  - **Do not quote the message you are replying to.** The sender already saw it; the TUI already renders it. Lead with the answer.
25
25
  - **Use IRC, not terminal tools, to learn about peers.** Do not `grep` artifacts, read other sessions' JSONL files, or shell-poke around to figure out what another agent is doing. DM them — they have the live answer and you do not.
26
26
  - **One round-trip is enough.** Replies arrive synchronously when the recipient is reachable. Do not follow up with "did you get my message?" — they did. If `delivered` is empty or the result was `failed`, the peer is unavailable; move on or report the blocker, do not retry in a loop.
27
- - **Stay terse.** A DM is a chat message, not a memo. One question per send when you can. Share file paths and artifacts via `local://` / `memory://` / `artifact://` URLs instead of pasting blobs.
27
+ - **Stay terse.** A DM is a chat message, not a memo. One question per send when you can. Share file paths and artifacts via `local://` / `artifact://` URLs instead of pasting blobs.
28
28
  - **Address peers by id.** Use the exact id from `op: "list"` (e.g. `0-AuthLoader`, `0-Main`). Do not invent friendly names.
29
29
  - **Do not IRC for things a tool would answer.** If a `read`, `grep`, or build command would resolve the question, do that first.
30
30
  - **When you receive an IRC message, answer it before continuing.** The recipient injects the question + your auto-reply into your history; address it directly, do not repeat it back to the user.
@@ -8,7 +8,7 @@ Read files, directories, archives, SQLite databases, images, documents, internal
8
8
 
9
9
  ## Parameters
10
10
 
11
- - `path` — required. Local path, internal URI (`agent://`, `artifact://`, `memory://`, `rule://`, `local://`), or URL. Append `:<sel>` for line ranges, raw mode, or special modes (e.g. `src/foo.ts:50-200`, `src/foo.ts:raw`, `db.sqlite:users:42`).
11
+ - `path` — required. Local path, internal URI (`agent://`, `artifact://`, `rule://`, `local://`), or URL. Append `:<sel>` for line ranges, raw mode, or special modes (e.g. `src/foo.ts:50-200`, `src/foo.ts:raw`, `db.sqlite:users:42`).
12
12
 
13
13
  ## Selectors
14
14
 
@@ -70,7 +70,7 @@ For `.sqlite`, `.sqlite3`, `.db`, `.db3`:
70
70
 
71
71
  # Internal URIs
72
72
 
73
- `agent://<id>`, `artifact://<id>`, `memory://root`, `rule://<name>`, and `local://<name>.md` resolve transparently and accept the same line selectors as filesystem paths. Use `artifact://<id>` to recover full output that a previous bash/eval/tool result spilled or truncated.
73
+ `agent://<id>`, `artifact://<id>`, `rule://<name>`, and `local://<name>.md` resolve transparently and accept the same line selectors as filesystem paths. Use `artifact://<id>` to recover full output that a previous bash/eval/tool result spilled or truncated.
74
74
 
75
75
  <critical>
76
76
  - You MUST use `read` for every file, directory, archive, and URL inspection. `cat`, `head`, `tail`, `less`, `more`, `ls`, `tar`, `unzip`, `curl`, `wget` are FORBIDDEN — any such bash call is a bug, regardless of how short or convenient it looks.
@@ -1,3 +1,4 @@
1
+ Compatibility-only legacy Hindsight helper. This prompt is retained for backend/tool-call compatibility and is not part of the public gajae-code coding harness tool surface.
1
2
  Search long-term memory for relevant information. Returns raw matching entries ranked by relevance.
2
3
 
3
4
  Use proactively — before answering questions about past conversations, user preferences, project decisions, or any topic where prior context would help accuracy. When in doubt, recall first.
@@ -1,3 +1,4 @@
1
+ Compatibility-only legacy Hindsight helper. This prompt is retained for backend/tool-call compatibility and is not part of the public gajae-code coding harness tool surface.
1
2
  Generate a synthesised answer by reasoning over long-term memory. Unlike `recall`, `reflect` blends relevant memories into a coherent response.
2
3
 
3
4
  Use for open-ended questions spanning many stored facts: "What do you know about this user?", "Summarize project decisions.", "What are my preferences for X?"
@@ -1,3 +1,4 @@
1
+ Compatibility-only legacy Hindsight helper. This prompt is retained for backend/tool-call compatibility and is not part of the public gajae-code coding harness tool surface.
1
2
  Store one or more facts in long-term memory for future sessions.
2
3
 
3
4
  Use for durable, reusable knowledge: user preferences, project decisions, architectural choices, anything that improves future responses.
package/src/sdk.ts CHANGED
@@ -291,7 +291,7 @@ export interface CreateAgentSessionOptions {
291
291
  taskDepth?: number;
292
292
  /** Current role-agent type/name for nested task sessions. */
293
293
  currentAgentType?: string;
294
- /** Parent Hindsight state to alias for subagent memory tools. */
294
+ /** Parent Hindsight state to alias for subagent private memory backend compatibility. */
295
295
  parentHindsightSessionState?: HindsightSessionState;
296
296
  /** Pre-allocated agent identity for IRC routing. Default: "0-Main" for top-level, parentTaskPrefix-derived for sub. */
297
297
  agentId?: string;
@@ -748,7 +748,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
748
748
  return;
749
749
  }
750
750
 
751
- void runtime.ctx.showOAuthSelector("login");
751
+ runtime.ctx.showProviderOnboarding();
752
752
  runtime.ctx.editor.setText("");
753
753
  },
754
754
  },
@@ -123,6 +123,7 @@ export interface ExecutorOptions {
123
123
  * if the resolved subagent model has no working credentials. See #985.
124
124
  */
125
125
  parentActiveModelPattern?: string;
126
+ parentSessionId?: string;
126
127
  thinkingLevel?: ThinkingLevel;
127
128
  outputSchema?: unknown;
128
129
  /** Parent task recursion depth (0 = top-level, 1 = first child, etc.) */
@@ -1094,6 +1095,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
1094
1095
  options.parentActiveModelPattern,
1095
1096
  modelRegistry,
1096
1097
  settings,
1098
+ options.parentSessionId,
1097
1099
  ),
1098
1100
  );
1099
1101
  if (authFallbackUsed && model) {
package/src/task/index.ts CHANGED
@@ -1310,6 +1310,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1310
1310
  taskDepth,
1311
1311
  modelOverride,
1312
1312
  parentActiveModelPattern,
1313
+ parentSessionId: this.session.getSessionId?.() ?? undefined,
1313
1314
  thinkingLevel: thinkingLevelOverride,
1314
1315
  outputSchema: effectiveOutputSchema,
1315
1316
  sessionFile: taskSessionFile,
@@ -1369,6 +1370,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1369
1370
  taskDepth,
1370
1371
  modelOverride,
1371
1372
  parentActiveModelPattern,
1373
+ parentSessionId: this.session.getSessionId?.() ?? undefined,
1372
1374
  thinkingLevel: thinkingLevelOverride,
1373
1375
  outputSchema: effectiveOutputSchema,
1374
1376
  sessionFile: taskSessionFile,
@@ -17,8 +17,6 @@ export class HindsightRecallTool implements AgentTool<typeof hindsightRecallSche
17
17
  readonly description = recallDescription;
18
18
  readonly parameters = hindsightRecallSchema;
19
19
  readonly strict = true;
20
- readonly loadMode = "discoverable";
21
- readonly summary = "Search hindsight memory for relevant prior context";
22
20
 
23
21
  constructor(private readonly session: ToolSession) {}
24
22
 
@@ -18,8 +18,6 @@ export class HindsightReflectTool implements AgentTool<typeof hindsightReflectSc
18
18
  readonly description = reflectDescription;
19
19
  readonly parameters = hindsightReflectSchema;
20
20
  readonly strict = true;
21
- readonly loadMode = "discoverable";
22
- readonly summary = "Reflect on recent work and write hindsight memory";
23
21
 
24
22
  constructor(private readonly session: ToolSession) {}
25
23
 
@@ -22,8 +22,6 @@ export class HindsightRetainTool implements AgentTool<typeof hindsightRetainSche
22
22
  readonly description = retainDescription;
23
23
  readonly parameters = hindsightRetainSchema;
24
24
  readonly strict = true;
25
- readonly loadMode = "discoverable";
26
- readonly summary = "Store important facts in hindsight memory";
27
25
 
28
26
  constructor(private readonly session: ToolSession) {}
29
27
 
@@ -36,9 +36,6 @@ import { DebugTool } from "./debug";
36
36
  import { EvalTool } from "./eval";
37
37
  import { FindTool } from "./find";
38
38
  import { GithubTool } from "./gh";
39
- import { HindsightRecallTool } from "./hindsight-recall";
40
- import { HindsightReflectTool } from "./hindsight-reflect";
41
- import { HindsightRetainTool } from "./hindsight-retain";
42
39
  import { InspectImageTool } from "./inspect-image";
43
40
  import { IrcTool } from "./irc";
44
41
  import { JobTool } from "./job";
@@ -76,9 +73,6 @@ export * from "./debug";
76
73
  export * from "./eval";
77
74
  export * from "./find";
78
75
  export * from "./gh";
79
- export * from "./hindsight-recall";
80
- export * from "./hindsight-reflect";
81
- export * from "./hindsight-retain";
82
76
  export * from "./image-gen";
83
77
  export * from "./inspect-image";
84
78
  export * from "./irc";
@@ -302,7 +296,10 @@ export function computeEssentialBuiltinNames(settings: Settings): string[] {
302
296
 
303
297
  /**
304
298
  * Public callable factory map. External callers may invoke `BUILTIN_TOOLS.read(session)` or
305
- * `BUILTIN_TOOLS[name](session)` to construct a tool directly.
299
+ * `BUILTIN_TOOLS[name](session)` to construct a public coding-harness tool directly.
300
+ *
301
+ * Hindsight memory helpers are intentionally excluded: memory is a private backend
302
+ * integration, not a public gajae-code tool surface.
306
303
  */
307
304
  export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
308
305
  read: s => new ReadTool(s),
@@ -337,9 +334,6 @@ export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
337
334
  web_search: s => new WebSearchTool(s),
338
335
  search_tool_bm25: SearchToolBm25Tool.createIf,
339
336
  write: s => new WriteTool(s),
340
- retain: HindsightRetainTool.createIf,
341
- recall: HindsightRecallTool.createIf,
342
- reflect: HindsightReflectTool.createIf,
343
337
  skill: SkillTool.createIf,
344
338
  goal: s => new GoalTool(s),
345
339
  };
@@ -460,11 +454,6 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
460
454
  ) {
461
455
  requestedTools.push("recipe");
462
456
  }
463
- if (session.settings.get("memory.backend") === "hindsight") {
464
- for (const name of ["recall", "retain", "reflect"]) {
465
- if (!requestedTools.includes(name)) requestedTools.push(name);
466
- }
467
- }
468
457
  }
469
458
  // Resolve effective tool discovery mode.
470
459
  // tools.discoveryMode takes precedence; mcp.discoveryMode is a back-compat alias for "mcp-only".
@@ -512,9 +501,6 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
512
501
  return true;
513
502
  }
514
503
  if (name === "recipe") return session.settings.get("recipe.enabled");
515
- if (name === "retain" || name === "recall" || name === "reflect") {
516
- return session.settings.get("memory.backend") === "hindsight";
517
- }
518
504
  if (name === "task") {
519
505
  const maxDepth = session.settings.get("task.maxRecursionDepth") ?? 2;
520
506
  const currentDepth = session.taskDepth ?? 0;
package/src/tools/read.ts CHANGED
@@ -1031,7 +1031,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1031
1031
  }
1032
1032
 
1033
1033
  const collectedLines = streamResult.lines;
1034
- if (!rawSelector && maxColumns > 0) {
1034
+ if (!rawSelector && !shouldAddHashLines && maxColumns > 0) {
1035
1035
  for (let i = 0; i < collectedLines.length; i++) {
1036
1036
  const { text, wasTruncated } = truncateLine(collectedLines[i], maxColumns);
1037
1037
  if (wasTruncated) {
@@ -1789,8 +1789,9 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1789
1789
  // counts in `truncation` keep reflecting the source, not the trimmed
1790
1790
  // view — column truncation surfaces separately via `.limits()`.
1791
1791
  const rawSelector = isRawSelector(parsed);
1792
+ const shouldAddHashLines = !rawSelector && displayMode.hashLines;
1792
1793
  const maxColumns = resolveOutputMaxColumns(this.session.settings);
1793
- if (!rawSelector && maxColumns > 0) {
1794
+ if (!rawSelector && !shouldAddHashLines && maxColumns > 0) {
1794
1795
  for (let i = 0; i < collectedLines.length; i++) {
1795
1796
  const { text, wasTruncated } = truncateLine(collectedLines[i], maxColumns);
1796
1797
  if (wasTruncated) {
@@ -1824,7 +1825,6 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1824
1825
  getFileReadCache(this.session).recordContiguous(absolutePath, startLineDisplay, collectedLines);
1825
1826
  }
1826
1827
 
1827
- const shouldAddHashLines = !rawSelector && displayMode.hashLines;
1828
1828
  const shouldAddLineNumbers = rawSelector ? false : shouldAddHashLines ? false : displayMode.lineNumbers;
1829
1829
  let capturedDisplayContent: { text: string; startLine: number } | undefined;
1830
1830
  const formatText = (text: string, startNum: number): string => {