clementine-agent 1.18.197 → 1.18.199

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.
@@ -42,11 +42,26 @@ const PLANNER_PROMPT = [
42
42
  '- End each step prompt with "Deliver: <one-line return shape>".',
43
43
  ].join('\n');
44
44
  const RESEARCHER_PROMPT = [
45
- 'You are a per-item research specialist. You receive ONE specific item to investigate (one lead, one account, one file, one topic).',
45
+ 'You are a per-item research specialist. You receive ONE specific item to investigate (one lead, one account, one domain, one file, one topic).',
46
46
  '',
47
- 'Use your bounded tools to gather the requested information. Return a ONE-PARAGRAPH summary in the format the parent specified.',
47
+ '## Tool access (1.18.198)',
48
48
  '',
49
- 'NEVER return raw tool output, full lists, or unbounded data. If a tool returns 50KB of JSON, extract only the fields you need and discard the rest.',
49
+ 'You INHERIT every tool the parent agent has access to: Bash, Read, Grep, Glob, WebSearch, WebFetch, AND every MCP tool the parent has wired (dataforseo, brightdata, Salesforce, Gmail, Composio integrations, etc.). If the parent has it, you have it.',
50
+ '',
51
+ 'The parent\'s dispatch prompt names the SPECIFIC tool you should use. Use exactly that tool. If the prompt is vague ("enrich this domain"), pick the most appropriate read-only tool from your inherited surface and proceed.',
52
+ '',
53
+ '## Safety bounds (behavior, not allowlist)',
54
+ '',
55
+ 'You are READ-ONLY. Never call:',
56
+ '- `Edit`, `Write`, `NotebookEdit` (mutate files)',
57
+ '- Any MCP tool whose name contains `send_`, `create_`, `update_`, `delete_`, `post_`, `apply_`, `move_`, `rename_`, `archive_`, `set_`, `add_`, `remove_`, `enable_`, `disable_`, `subscribe_`, `unsubscribe_`, `assign_`, `cancel_`, `approve_`',
58
+ '- Bash commands containing `rm `, `mv `, `>>`, `>` (except for piping to `head`/`awk`), `git commit`, `git push`, `sf data ... update`, `sf data ... delete`, or any shell side-effect',
59
+ '',
60
+ 'If you cannot complete the request read-only, say so in one line — do not improvise a mutation.',
61
+ '',
62
+ '## Output discipline',
63
+ '',
64
+ 'Return a ONE-PARAGRAPH summary in the format the parent specified. Never raw tool output, never full lists, never unbounded data dumps. If a tool returns 50KB of JSON, extract only the requested fields and discard the rest — your job is to compress.',
50
65
  '',
51
66
  'If you cannot find the requested data, say so in one line. Do not speculate.',
52
67
  ].join('\n');
@@ -177,18 +192,36 @@ export function buildAgentMap(opts = {}) {
177
192
  maxTurns: 1,
178
193
  };
179
194
  // Researcher: haiku, per-item investigation. Cheap fan-out target.
180
- // No Bash — researcher is read-only fanout, must not mutate state.
195
+ //
196
+ // 1.18.198 — NO `tools` allowlist. Researcher inherits every tool the
197
+ // parent has access to (Bash, Read, MCP wildcards, etc.). The earlier
198
+ // hardcoded ['Read', 'Grep', 'Glob', 'WebSearch', 'WebFetch'] blocked
199
+ // researcher from using the parent's MCP servers — when Ross dispatched
200
+ // "Parallel SEO enrichment for 13 domains" the subagent couldn't call
201
+ // `mcp__dataforseo__*` because it wasn't in the allowlist. Result: the
202
+ // subagent said "I can't do that" and Ross fell back to running 25
203
+ // sequential MCP calls in his own turn, defeating the fan-out.
204
+ //
205
+ // Read-only behavior is enforced in RESEARCHER_PROMPT (behavior class:
206
+ // no `Edit`/`Write`, no MCP tools containing send_/create_/update_/
207
+ // delete_/etc.). The prompt is the contract; the SDK lets the subagent
208
+ // inherit everything from the parent.
181
209
  map['researcher'] = {
182
210
  description: [
183
211
  'Use this subagent to investigate ONE specific item — a single',
184
- 'lead, account, file, web page, or topic — and return a',
212
+ 'lead, account, domain, file, web page, or topic — and return a',
185
213
  'one-paragraph summary. Spawn it in PARALLEL via the Agent tool',
186
- 'with one subagent per item when the planner returns multiple',
187
- 'research steps. Read-only: never mutates state. Cheap (Haiku).',
214
+ 'with one subagent per item for batch fan-out. Read-only: never',
215
+ 'mutates state (Haiku, inherits parent tool surface).',
216
+ '',
217
+ 'When dispatching, NAME THE SPECIFIC TOOL in the prompt (e.g.',
218
+ '"call mcp__dataforseo__google_domain_rank_overview for domain X")',
219
+ 'rather than describing the goal abstractly ("enrich this domain").',
188
220
  ].join(' '),
189
221
  prompt: RESEARCHER_PROMPT,
190
222
  model: 'haiku',
191
- tools: ['Read', 'Grep', 'Glob', 'WebSearch', 'WebFetch'],
223
+ // NO `tools` field inherit from parent. See RESEARCHER_PROMPT for
224
+ // read-only safety enforcement.
192
225
  effort: 'low',
193
226
  maxTurns: 15,
194
227
  };
@@ -141,7 +141,16 @@ const BEHAVIORAL_POSTURE = `## How you operate
141
141
 
142
142
  6. **Single, targeted action** (read this specific file, write this output, call this one MCP tool, send this one message) → do it yourself in your own turn. Direct tool use is correct when the scope is small and known.
143
143
 
144
- **The northstar.** A request like "find that coach project locally and build a report" should look like: you dispatch \`discovery\` to find the project (returns paths), then you Read the specific README it returned (one targeted Read), then you dispatch a worker subagent or do the report-write yourself depending on scope. NOT: you run a recursive \`Glob\` then 20 Reads in your own turn.`;
144
+ **The northstar.** A request like "find that coach project locally and build a report" should look like: you dispatch \`discovery\` to find the project (returns paths), then you Read the specific README it returned (one targeted Read), then you dispatch a worker subagent or do the report-write yourself depending on scope. NOT: you run a recursive \`Glob\` then 20 Reads in your own turn.
145
+
146
+ **Dispatch-prompt rule (1.18.198).** When you dispatch to a subagent, NAME THE SPECIFIC TOOL the subagent should use in your prompt. Subagents inherit your full tool surface (every MCP your parent has access to is also visible to them), but they often can't tell from a goal-only prompt which tool to pick. Be explicit:
147
+
148
+ - ❌ Vague: "Enrich these 13 law firm domains."
149
+ - ✅ Specific: "For each domain in the list, call \`mcp__dataforseo__dataforseo_labs_google_domain_rank_overview\` and return: organic_keywords, etv, top-3 ranked keywords. Read-only — never call any MCP tool whose name contains send_/create_/update_/delete_."
150
+
151
+ The subagent's job is execution, not tool selection. You did the orchestration thinking; pass the answer through to them. A subagent that doesn't know which tool to use will either guess wrong or refuse — both waste a dispatch.
152
+
153
+ For parallel fan-out (25 contacts to enrich, 30 records to look up), dispatch 25 subagents in ONE message, each with the same tool name but a different per-item input. The SDK runs them concurrently.`;
145
154
  /**
146
155
  * Read the long-term memory block for an autonomous run (cron, team-task).
147
156
  * Returns the agent-specific MEMORY.md when a hired agent is active, the
@@ -2431,14 +2431,38 @@ export class Gateway {
2431
2431
  });
2432
2432
  // Wire Composio + external MCP only for real chat. Builder
2433
2433
  // skips entirely — builder turns never call tools.
2434
+ //
2435
+ // 1.18.199 — `fullSurface: true` (NOT per-turn scopeText routing).
2436
+ //
2437
+ // The previous per-message routing was a regression: each chat
2438
+ // turn called `routeToolSurface(originalText)` and only loaded
2439
+ // MCP servers that matched THAT message's text. When the owner
2440
+ // sent a one-word reply like "sure" mid-conversation, zero MCPs
2441
+ // matched → zero servers registered → Ross said "DataForSEO
2442
+ // isn't in scope for this session context" mid-task. Verified
2443
+ // live on 2026-05-12 at 13:35:33.
2444
+ //
2445
+ // The right structural fix: chat always loads the agent's
2446
+ // full profile-allowed MCP surface. The profile's
2447
+ // `allowedComposioToolkits` / `allowedMcpServers` still bound
2448
+ // what each agent can see (Ross gets his scope, Sasha gets
2449
+ // hers). Within those bounds, every server registers every
2450
+ // turn — tools don't vanish mid-conversation. The SDK's
2451
+ // `ENABLE_TOOL_SEARCH=auto:5` (execution-policy.ts) still
2452
+ // defers individual tool-schema loading until needed, so the
2453
+ // per-turn token cost stays bounded even with many servers
2454
+ // registered.
2455
+ //
2456
+ // The skill-resolver still runs above this point — it
2457
+ // contributes the SKILL PROMPT BLOCK to system context. It
2458
+ // simply no longer affects MCP server registration. That
2459
+ // experiment (1.18.170 `skillHintedMcpServers`) caused more
2460
+ // problems than it solved.
2434
2461
  const chatMcp = isBuilderSession
2435
2462
  ? null
2436
2463
  : await buildExtraMcpForRunAgent({
2437
- scopeText: originalText,
2464
+ fullSurface: true,
2438
2465
  profile: resolvedProfile,
2439
- ...(resolvedSkills && resolvedSkills.hintedMcpServers.length > 0
2440
- ? { skillHintedMcpServers: resolvedSkills.hintedMcpServers }
2441
- : {}),
2442
2466
  });
2443
2467
  // Vault context (SOUL.md / MEMORY.md / AGENTS.md + optional
2444
2468
  // profile body) — real chat only. Builder gets just its own
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clementine-agent",
3
- "version": "1.18.197",
3
+ "version": "1.18.199",
4
4
  "description": "Clementine — Personal AI Assistant (TypeScript)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",