clementine-agent 1.18.175 → 1.18.176

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.
@@ -75,6 +75,10 @@ export interface RunAgentOptions {
75
75
  /** Optional explicit allowedTools list. When unset, falls back to a sensible default
76
76
  * including Agent (so subagents can be spawned) + core SDK tools + Clementine MCP. */
77
77
  allowedTools?: string[];
78
+ /** Extra tools to pre-approve without making their built-in tools visible to
79
+ * the main agent. Useful when the main agent may only call Agent, but the
80
+ * forced subagent still needs pre-approved MCP/Clementine tools. */
81
+ permissionTools?: string[];
78
82
  /** SDK permission mode. Defaults to dontAsk so allowedTools is enforceable.
79
83
  * Only explicit operator/full-surface paths should request bypassPermissions. */
80
84
  permissionMode?: ExecutionPermissionMode;
@@ -254,6 +254,27 @@ export async function runAgent(prompt, opts) {
254
254
  clementineServerName: TOOLS_SERVER,
255
255
  permissionMode: opts.permissionMode,
256
256
  });
257
+ const permissionToolPolicy = opts.permissionTools
258
+ ? buildExecutionToolPolicy({
259
+ requestedTools: opts.permissionTools,
260
+ defaultBuiltins: CORE_TOOLS_FOR_AGENT_PARENT,
261
+ mcpServerNames: policyMcpServerNames,
262
+ clementineServerName: TOOLS_SERVER,
263
+ permissionMode: opts.permissionMode,
264
+ })
265
+ : null;
266
+ const sdkAllowedTools = permissionToolPolicy
267
+ ? Array.from(new Set([...toolPolicy.allowedTools, ...permissionToolPolicy.allowedTools])).sort()
268
+ : toolPolicy.allowedTools;
269
+ const clementineToolAllowlist = (() => {
270
+ if (!permissionToolPolicy)
271
+ return toolPolicy.clementineToolAllowlist;
272
+ const parts = [toolPolicy.clementineToolAllowlist, permissionToolPolicy.clementineToolAllowlist]
273
+ .flatMap(v => v.split(',').map(s => s.trim()).filter(Boolean));
274
+ if (parts.includes('*'))
275
+ return '*';
276
+ return Array.from(new Set(parts)).sort().join(',');
277
+ })();
257
278
  // SDK accepts a Record<string, McpServerConfig> here. We cast on
258
279
  // assignment because we mix the always-on Clementine stdio server
259
280
  // with caller-supplied servers of various types.
@@ -267,7 +288,7 @@ export async function runAgent(prompt, opts) {
267
288
  CLEMENTINE_HOME: BASE_DIR,
268
289
  ...(opts.profile?.slug ? { CLEMENTINE_TEAM_AGENT: opts.profile.slug } : {}),
269
290
  CLEMENTINE_INTERACTION_SOURCE: interactionSourceForSession(opts.sessionKey, source),
270
- CLEMENTINE_TOOL_ALLOWLIST: toolPolicy.clementineToolAllowlist,
291
+ CLEMENTINE_TOOL_ALLOWLIST: clementineToolAllowlist,
271
292
  },
272
293
  },
273
294
  ...baseMcpServers,
@@ -407,7 +428,7 @@ export async function runAgent(prompt, opts) {
407
428
  // callers can mix stdio + http + sse server shapes.
408
429
  mcpServers: mcpServers,
409
430
  tools: toolPolicy.builtinTools,
410
- allowedTools: toolPolicy.allowedTools,
431
+ allowedTools: sdkAllowedTools,
411
432
  permissionMode: toolPolicy.permissionMode,
412
433
  ...(sessionStore ? { sessionStore } : {}),
413
434
  ...(toolPolicy.allowDangerouslySkipPermissions
@@ -447,7 +468,7 @@ export async function runAgent(prompt, opts) {
447
468
  maxBudgetUsd: maxBudgetUsd ?? 'uncapped',
448
469
  agentCount: Object.keys(agents).length,
449
470
  allowedToolCount: allowedTools.length,
450
- sdkAllowedToolCount: toolPolicy.allowedTools.length,
471
+ sdkAllowedToolCount: sdkAllowedTools.length,
451
472
  builtinToolCount: toolPolicy.builtinTools.length,
452
473
  permissionMode: toolPolicy.permissionMode,
453
474
  mcpServerCount: Object.keys(mcpServers).length,
@@ -739,7 +760,7 @@ export async function runAgent(prompt, opts) {
739
760
  ...(usage ? { usage } : {}),
740
761
  runId,
741
762
  permissionMode: toolPolicy.permissionMode,
742
- allowedToolsApplied: toolPolicy.allowedTools,
763
+ allowedToolsApplied: sdkAllowedTools,
743
764
  builtinToolsApplied: toolPolicy.builtinTools,
744
765
  mcpServersApplied: Object.keys(mcpServers),
745
766
  };
@@ -417,6 +417,9 @@ export async function runSkill(name, options = {}) {
417
417
  // the parent's context shape predictable and prevents it from
418
418
  // doing data-heavy work itself even if the LLM disagrees.
419
419
  allowedTools: ['Agent'],
420
+ // SDK permissions are session-level, so the worker's tools still
421
+ // need to be pre-approved even though the parent only sees Agent.
422
+ permissionTools: ['Agent', ...effectiveTools],
420
423
  // Force-routing: SDK wraps the prompt with "Use the skill-worker
421
424
  // agent to handle this request" so dispatch is the natural
422
425
  // first action.
@@ -2368,7 +2368,10 @@ export class Gateway {
2368
2368
  if (scheduledSkillName) {
2369
2369
  const { runSkill } = await import('../agent/run-skill.js');
2370
2370
  const configuredCap = tier >= 2 ? BUDGET.cronT2 : BUDGET.cronT1;
2371
- const scheduledSkillBudget = configuredCap > 0 ? configuredCap : undefined;
2371
+ // Pass 0 through intentionally. It means "uncapped" and must
2372
+ // override skill-local clementine.limits.maxBudgetUsd values when
2373
+ // the operator has disabled global cron budgets.
2374
+ const scheduledSkillBudget = configuredCap > 0 ? configuredCap : 0;
2372
2375
  logger.info({ jobName, skill: scheduledSkillName, agentSlug, tier, wallMs, path: 'run_skill' }, 'Routing scheduled skill through runSkill');
2373
2376
  const skillResult = await runSkill(scheduledSkillName, {
2374
2377
  sessionKey: `cron:${jobName}`,
@@ -2380,7 +2383,7 @@ export class Gateway {
2380
2383
  projectWorkDir: workDir,
2381
2384
  model,
2382
2385
  ...(maxTurns ? { maxTurns } : {}),
2383
- ...(scheduledSkillBudget !== undefined ? { maxBudgetUsd: scheduledSkillBudget } : {}),
2386
+ maxBudgetUsd: scheduledSkillBudget,
2384
2387
  abortSignal: cronAc.signal,
2385
2388
  context: `[Scheduled skill: ${jobName}]`,
2386
2389
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clementine-agent",
3
- "version": "1.18.175",
3
+ "version": "1.18.176",
4
4
  "description": "Clementine — Personal AI Assistant (TypeScript)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",