@nanhara/hara 0.102.0 → 0.103.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/CHANGELOG.md +16 -0
- package/dist/agent/loop.js +7 -1
- package/dist/index.js +5 -1
- package/dist/tools/agent.js +16 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,22 @@ All notable changes to `@nanhara/hara`.
|
|
|
5
5
|
> Versioning (pre-1.0, SemVer-style): the **minor** (middle) number bumps for a **new feature**; the
|
|
6
6
|
> **patch** (last) number bumps for **optimizations/fixes of existing features**.
|
|
7
7
|
|
|
8
|
+
## 0.103.0 — the project-analysis SOP (why hara felt slow on "analyze this repo")
|
|
9
|
+
|
|
10
|
+
The execution layer could always parallelize reads and fan out read-only sub-agents — but nothing
|
|
11
|
+
TAUGHT the model, so it explored one call per turn. Distilled from codex's prompt discipline and
|
|
12
|
+
Claude Code's Explore-agent pattern:
|
|
13
|
+
|
|
14
|
+
- **System prompt playbook**: batch independent tool calls in one response (reads execute in
|
|
15
|
+
parallel); analyzing a project starts with a ONE-batch wide sweep (manifest + README + build/CI
|
|
16
|
+
config) then narrow grep/glob; more than ~3 searches → fan out `agent` sub-agents, several in one
|
|
17
|
+
response.
|
|
18
|
+
- **`agent` tool grows WHEN-TO-USE / WHEN-NOT-TO-USE guidance** (CC's heuristic): narrow lookups go
|
|
19
|
+
to direct tools; open-ended "how does X work across the codebase" goes to sub-agents.
|
|
20
|
+
- **Built-in `explore` persona** — `agent(role:"explore")` works with zero setup: read-only, parallel
|
|
21
|
+
searches, excerpts not whole files, returns conclusions with path:line refs, never dumps. A
|
|
22
|
+
user-defined explore role still wins.
|
|
23
|
+
|
|
8
24
|
## 0.102.0 — a slow network never feels dead
|
|
9
25
|
|
|
10
26
|
Jeff + a designer colleague both hit the same thing: press Enter on a slow connection and hara
|
package/dist/agent/loop.js
CHANGED
|
@@ -49,7 +49,13 @@ const HARA_SYSTEM = (cwd) => `You are hara, a coding agent running in the user's
|
|
|
49
49
|
Working directory: ${cwd}
|
|
50
50
|
Be concise and direct. Use the provided tools to read files, edit/write files, and run shell
|
|
51
51
|
commands. Prefer small, verifiable steps; edit existing files with edit_file rather than rewriting
|
|
52
|
-
them whole.
|
|
52
|
+
them whole. Batch INDEPENDENT tool calls in a single response — especially reads (read_file / grep /
|
|
53
|
+
glob / ls run in PARALLEL when requested together); one-call-per-turn exploration is the slowest thing
|
|
54
|
+
you can do. When analyzing a project, start wide in ONE batch — manifest (package.json / Cargo.toml /
|
|
55
|
+
pyproject.toml / go.mod), README, build/CI config — then chase only what the task needs with narrow
|
|
56
|
+
grep/glob; don't read whole large files when a targeted search answers the question. For broad,
|
|
57
|
+
open-ended exploration (more than ~3 searches), spawn \`agent\` sub-agents — several in one response for
|
|
58
|
+
independent questions (role "explore") — each returns conclusions, not dumps. For a multi-step task, call \`todo_write\` to plan a short checklist and keep it updated as
|
|
53
59
|
you go (one item in_progress at a time) — skip it for trivial one-step tasks. You have a persistent
|
|
54
60
|
memory: use memory_search before answering about prior decisions,
|
|
55
61
|
conventions, or the user's preferences, and memory_write to proactively save durable facts you learn.
|
package/dist/index.js
CHANGED
|
@@ -36,6 +36,7 @@ import { addJob, removeJob, setEnabled, resolveJob, loadJobs, recordRun, logPath
|
|
|
36
36
|
import { runTick, runJobOnce, selfArgv } from "./cron/runner.js";
|
|
37
37
|
import { installScheduler, uninstallScheduler, isInstalled } from "./cron/install.js";
|
|
38
38
|
import { getTools } from "./tools/registry.js";
|
|
39
|
+
import { EXPLORE_SYSTEM } from "./tools/agent.js";
|
|
39
40
|
import { createAnthropicProvider } from "./providers/anthropic.js";
|
|
40
41
|
import { createOpenAIProvider } from "./providers/openai.js";
|
|
41
42
|
import { qwenDeviceLogin, getValidQwenAuth } from "./providers/qwen-oauth.js";
|
|
@@ -765,6 +766,9 @@ async function maybeAutoCompact(provider, history, meta, stats, cfg, notify) {
|
|
|
765
766
|
async function runSubagent(cfg, baseProvider, cwd, sandbox, projectContext, stats, task, roleId) {
|
|
766
767
|
const roles = loadRoles(cwd);
|
|
767
768
|
const role = roleId ? roles.find((r) => r.id === roleId) : undefined;
|
|
769
|
+
// Built-in explore persona: `agent(role:"explore")` works with ZERO user setup (a user-defined
|
|
770
|
+
// explore role still wins — it was found above and carries its own system).
|
|
771
|
+
const builtinSystem = !role && roleId === "explore" ? EXPLORE_SYSTEM : undefined;
|
|
768
772
|
const __subModel = effectiveRoleModel(role?.model, cfg.model);
|
|
769
773
|
const provider = __subModel ? ((await buildProvider({ ...cfg, model: __subModel })) ?? baseProvider) : baseProvider;
|
|
770
774
|
// A sub-agent runs full-auto + UNCONFIRMED + parallel, so it is ALWAYS read-only — a role may narrow
|
|
@@ -780,7 +784,7 @@ async function runSubagent(cfg, baseProvider, cwd, sandbox, projectContext, stat
|
|
|
780
784
|
projectContext,
|
|
781
785
|
memory: memoryDigest(cwd),
|
|
782
786
|
stats,
|
|
783
|
-
systemOverride: role?.system,
|
|
787
|
+
systemOverride: role?.system ?? builtinSystem,
|
|
784
788
|
toolFilter,
|
|
785
789
|
quiet: true,
|
|
786
790
|
});
|
package/dist/tools/agent.js
CHANGED
|
@@ -2,11 +2,24 @@
|
|
|
2
2
|
// turn run in PARALLEL (kind "read" → concurrent), making the footer's ⛁ count real. Sub-agents are
|
|
3
3
|
// read-only by default (safe to parallelize); the actual spawn is provided via ctx.spawn.
|
|
4
4
|
import { registerTool } from "./registry.js";
|
|
5
|
+
/** Built-in persona for `role: "explore"` (no setup needed — index.ts falls back to this when the
|
|
6
|
+
* user hasn't defined an explore role). Claude-Code's Explore-agent playbook: read-only, parallel,
|
|
7
|
+
* excerpts-not-files, conclusions-not-dumps. */
|
|
8
|
+
export const EXPLORE_SYSTEM = "You are a fast, READ-ONLY codebase explorer. Navigate with grep/glob/ls/read_file and be quick: " +
|
|
9
|
+
"issue your searches and file reads as MULTIPLE PARALLEL tool calls in one round whenever they are " +
|
|
10
|
+
"independent — never one-per-turn. Read targeted excerpts, not whole files. You cannot modify anything. " +
|
|
11
|
+
"Answer with CONCLUSIONS: the finding, the relevant paths with line references, and what they mean for " +
|
|
12
|
+
"the question — never dump raw file contents. Match your depth to the task: a quick lookup stays quick; " +
|
|
13
|
+
"an architecture question deserves a thorough sweep across naming conventions and directories.";
|
|
5
14
|
registerTool({
|
|
6
15
|
name: "agent",
|
|
7
|
-
description: "Delegate an independent sub-task to a fresh sub-agent and get its
|
|
8
|
-
"
|
|
9
|
-
"
|
|
16
|
+
description: "Delegate an independent sub-task to a fresh READ-ONLY sub-agent and get its conclusions. " +
|
|
17
|
+
"WHEN TO USE: open-ended exploration ('how does X work across the codebase', 'find everything that touches Y') " +
|
|
18
|
+
"that would take more than ~3 searches — pass role \"explore\" for a fast search specialist; and spawning " +
|
|
19
|
+
"SEVERAL agents in ONE response for independent questions (they run in parallel). " +
|
|
20
|
+
"WHEN NOT TO USE: reading a specific known file (read_file), finding one symbol (grep), or searching " +
|
|
21
|
+
"within 2-3 known files — direct tools are faster. Never for edits. " +
|
|
22
|
+
"Pass a `role` id to use that role's persona + tools.",
|
|
10
23
|
input_schema: {
|
|
11
24
|
type: "object",
|
|
12
25
|
properties: {
|