@atlasharness/atlascode 0.1.64 → 0.1.66

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 (2) hide show
  1. package/dist/cli.js +197 -21
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -37092,9 +37092,9 @@ function formatAgentLine(agent) {
37092
37092
  function getPrompt(agents) {
37093
37093
  const list = agents.length > 0 ? agents.map(formatAgentLine).join(`
37094
37094
  `) : "- general-purpose: General-purpose agent for researching and executing multi-step tasks.";
37095
- return "Launch a subagent to run a self-contained task in an isolated context. " + "Provide a short description (3-5 words) and a fully self-contained prompt " + "(the subagent cannot see this conversation). " + "Be cost-aware about delegating: prefer to do the work inline in this " + "conversation for a small task with a known, bounded target (a single-file " + "edit, a quick lookup, a change you can finish without broad exploration) — " + "spawning a subagent has overhead. Delegate when the task is genuinely " + "parallelizable or would otherwise flood this context with material you do " + "not need to keep (a broad multi-file search, an isolated multi-step " + "implementation, or independent work that can run alongside your own). Keep " + "each delegated brief narrow and evidence-focused: name the exact goal, the " + "files or area, and the expected deliverable rather than a broad " + '"figure this out." Because the subagent cannot see this conversation, its ' + "prompt must be fully self-contained — state every constraint, file, and " + "reporting requirement it needs. " + `Available agent types and the tools they have access to:
37095
+ return "Launch a subagent to run a self-contained task in an isolated context. " + "Provide a short description (3-5 words) and a fully self-contained prompt " + "(the subagent cannot see this conversation). " + "Be cost-aware about delegating: prefer to do the work inline in this " + "conversation for a small task with a known, bounded target (a single-file " + "edit, a quick lookup, a change you can finish without broad exploration) — " + "spawning a subagent has overhead. Delegate when the task is genuinely " + "parallelizable or would otherwise flood this context with material you do " + "not need to keep (a broad multi-file search, an isolated multi-step " + "implementation, or independent work that can run alongside your own). Keep " + "each delegated brief narrow and evidence-focused: name the exact goal, the " + "files or area, and the expected deliverable rather than a broad " + '"figure this out." Because the subagent cannot see this conversation, its ' + "prompt must be fully self-contained — state every constraint, file, and " + "reporting requirement it needs. " + "Subagents run in the background by default; you will receive a " + "task-notification when one completes — do not poll or sleep waiting for " + "it. Set run_in_background to false only when you need the result before " + "you can proceed. Use background for genuinely parallel work, not to defer " + "a result you need immediately. " + `Available agent types and the tools they have access to:
37096
37096
  ${list}
37097
- ` + `The ${AGENT_TOOL_NAME} tool runs the subagent and returns its final result ` + "when it completes; act on that result once it is returned.";
37097
+ ` + `The ${AGENT_TOOL_NAME} tool runs the subagent and returns its final result ` + "when it completes; act on that result once it is returned. " + "Do not predict or assume what the subagent will find — wait for its " + "returned result and act on what it actually reports.";
37098
37098
  }
37099
37099
  var init_prompt = () => {};
37100
37100
 
@@ -37136,13 +37136,112 @@ async function runAgent(args) {
37136
37136
  turns: loopResult.turns
37137
37137
  };
37138
37138
  }
37139
+ function wrapPermissionGateForBackground(gate, onNeedsInput) {
37140
+ if (!gate)
37141
+ return;
37142
+ return async (tool, input, callContext) => {
37143
+ const verdict = await gate(tool, input, callContext);
37144
+ if (verdict.ask) {
37145
+ onNeedsInput({
37146
+ toolName: tool.name,
37147
+ reason: verdict.reason
37148
+ });
37149
+ }
37150
+ return verdict;
37151
+ };
37152
+ }
37153
+ async function runAsyncAgentLifecycle(args) {
37154
+ const { description, toolUseId, signal, agentId } = args;
37155
+ const wrappedCheckPermission = wrapPermissionGateForBackground(args.checkPermission, (req) => {
37156
+ enqueueAgentNotification({
37157
+ taskId: agentId,
37158
+ description,
37159
+ status: "needs_input",
37160
+ inputRequest: `Permission required for ${req.toolName}${req.reason ? `: ${req.reason}` : ""}`,
37161
+ ...toolUseId ? { toolUseId } : {}
37162
+ });
37163
+ });
37164
+ try {
37165
+ const { result } = await runAgent({
37166
+ ...args,
37167
+ checkPermission: wrappedCheckPermission
37168
+ });
37169
+ const finalMessage = result.content.map((b) => b.text).join("");
37170
+ enqueueAgentNotification({
37171
+ taskId: agentId,
37172
+ description,
37173
+ status: "completed",
37174
+ finalMessage: finalMessage || undefined,
37175
+ usage: {
37176
+ totalTokens: result.totalTokens,
37177
+ toolUses: result.totalToolUseCount,
37178
+ durationMs: result.totalDurationMs
37179
+ },
37180
+ ...toolUseId ? { toolUseId } : {}
37181
+ });
37182
+ } catch (err) {
37183
+ if (signal?.aborted) {
37184
+ enqueueAgentNotification({
37185
+ taskId: agentId,
37186
+ description,
37187
+ status: "killed",
37188
+ ...toolUseId ? { toolUseId } : {}
37189
+ });
37190
+ return;
37191
+ }
37192
+ enqueueAgentNotification({
37193
+ taskId: agentId,
37194
+ description,
37195
+ status: "failed",
37196
+ error: err instanceof Error ? err.message : String(err),
37197
+ ...toolUseId ? { toolUseId } : {}
37198
+ });
37199
+ }
37200
+ }
37139
37201
  var init_runAgent = __esm(() => {
37140
37202
  init_query2();
37141
37203
  init_agentToolUtils();
37204
+ init_localAgentTask();
37205
+ });
37206
+
37207
+ // src/engine/tools/agent/backgroundTracker.ts
37208
+ function trackBackgroundAgent(p) {
37209
+ const handled = p.then(() => {}, () => {});
37210
+ pendingBackgroundAgents.add(handled);
37211
+ handled.finally(() => {
37212
+ pendingBackgroundAgents.delete(handled);
37213
+ });
37214
+ }
37215
+ function hasPendingBackgroundAgents() {
37216
+ return pendingBackgroundAgents.size > 0;
37217
+ }
37218
+ async function drainPendingBackgroundAgents(signal) {
37219
+ if (pendingBackgroundAgents.size === 0)
37220
+ return;
37221
+ const promises = Array.from(pendingBackgroundAgents);
37222
+ if (signal?.aborted)
37223
+ return;
37224
+ await Promise.allSettled(promises);
37225
+ }
37226
+ function resetBackgroundAgentTracker() {
37227
+ pendingBackgroundAgents.clear();
37228
+ }
37229
+ var pendingBackgroundAgents;
37230
+ var init_backgroundTracker = __esm(() => {
37231
+ pendingBackgroundAgents = new Set;
37142
37232
  });
37143
37233
 
37144
37234
  // src/engine/tools/agent/AgentTool.ts
37145
37235
  import { randomUUID as randomUUID5 } from "crypto";
37236
+ function isAgentBackgroundByDefault() {
37237
+ return !isEnvTruthy(process.env.ATLAS_AGENT_DEFAULT_FOREGROUND);
37238
+ }
37239
+ function shouldRunInBackground(runInBg) {
37240
+ if (isAgentBackgroundByDefault()) {
37241
+ return runInBg !== false;
37242
+ }
37243
+ return !!runInBg;
37244
+ }
37146
37245
  function resolveAgentDefinition(subagentType, agents) {
37147
37246
  if (!subagentType)
37148
37247
  return GENERAL_PURPOSE_AGENT;
@@ -37164,6 +37263,10 @@ var init_AgentTool = __esm(() => {
37164
37263
  init_prompt();
37165
37264
  init_runAgent();
37166
37265
  init_coordinator();
37266
+ init_task2();
37267
+ init_localAgentTask();
37268
+ init_shared();
37269
+ init_backgroundTracker();
37167
37270
  AGENT_TOOL_INPUT_SCHEMA = {
37168
37271
  type: "object",
37169
37272
  properties: {
@@ -37182,6 +37285,10 @@ var init_AgentTool = __esm(() => {
37182
37285
  model: {
37183
37286
  enum: ["small", "premium", "fast"],
37184
37287
  description: "Optional model override for this agent. Takes precedence over the agent definition's model. If omitted, inherits from the parent."
37288
+ },
37289
+ run_in_background: {
37290
+ type: "boolean",
37291
+ description: "Set to true to run this agent in the background. You will be notified when it completes."
37185
37292
  }
37186
37293
  },
37187
37294
  required: ["description", "prompt"]
@@ -37218,6 +37325,13 @@ var init_AgentTool = __esm(() => {
37218
37325
  ` + text
37219
37326
  };
37220
37327
  }
37328
+ if (c && c.status === "async_launched") {
37329
+ return {
37330
+ type: "tool_result",
37331
+ tool_use_id: toolUseID,
37332
+ content: "[agent launched in background] agentId=" + (c.agentId ?? "") + " output=" + (c.outputFile ?? "")
37333
+ };
37334
+ }
37221
37335
  return {
37222
37336
  type: "tool_result",
37223
37337
  tool_use_id: toolUseID,
@@ -37235,6 +37349,39 @@ var init_AgentTool = __esm(() => {
37235
37349
  const allowFanOut = isCoordinatorMode() && childSpawnDepth < MAX_WORKER_SPAWN_DEPTH;
37236
37350
  const resolvedTools = resolveAgentTools(agentDefinition, availableTools, allowFanOut).resolvedTools;
37237
37351
  const agentId = "agent-" + randomUUID5();
37352
+ if (shouldRunInBackground(input.run_in_background)) {
37353
+ const outputFile = getTaskOutputPath(agentId);
37354
+ const bgPromise = runAsyncAgentLifecycle({
37355
+ agentDefinition,
37356
+ prompt: input.prompt,
37357
+ tools: resolvedTools,
37358
+ modelProvider,
37359
+ parentRole,
37360
+ overrideRole: input.model,
37361
+ agentId,
37362
+ spawnDepth: childSpawnDepth,
37363
+ signal: ctx.signal,
37364
+ checkPermission: ctx.checkPermission,
37365
+ description: input.description
37366
+ }).catch((err) => {
37367
+ enqueueAgentNotification({
37368
+ taskId: agentId,
37369
+ description: input.description,
37370
+ status: "failed",
37371
+ error: err instanceof Error ? err.message : String(err)
37372
+ });
37373
+ });
37374
+ trackBackgroundAgent(bgPromise);
37375
+ return {
37376
+ data: {
37377
+ status: "async_launched",
37378
+ agentId,
37379
+ description: input.description,
37380
+ prompt: input.prompt,
37381
+ outputFile
37382
+ }
37383
+ };
37384
+ }
37238
37385
  const { result } = await runAgent({
37239
37386
  agentDefinition,
37240
37387
  prompt: input.prompt,
@@ -51573,6 +51720,7 @@ var init_agent = __esm(() => {
51573
51720
  init_forkSubagent();
51574
51721
  init_agentToolUtils();
51575
51722
  init_prompt();
51723
+ init_backgroundTracker();
51576
51724
  });
51577
51725
 
51578
51726
  // src/engine/tools/bash/bashPrompt.ts
@@ -79621,24 +79769,27 @@ function enqueueAgentNotification({
79621
79769
  usage,
79622
79770
  toolUseId,
79623
79771
  worktreePath,
79624
- worktreeBranch
79772
+ worktreeBranch,
79773
+ inputRequest
79625
79774
  }) {
79626
- let shouldEnqueue = false;
79627
- updateTaskState(taskId, setAppState, (task) => {
79628
- if (task.notified) {
79629
- return task;
79775
+ if (setAppState && status !== "needs_input") {
79776
+ let shouldEnqueue = false;
79777
+ updateTaskState(taskId, setAppState, (task) => {
79778
+ if (task.notified) {
79779
+ return task;
79780
+ }
79781
+ shouldEnqueue = true;
79782
+ return {
79783
+ ...task,
79784
+ notified: true
79785
+ };
79786
+ });
79787
+ if (!shouldEnqueue) {
79788
+ return;
79630
79789
  }
79631
- shouldEnqueue = true;
79632
- return {
79633
- ...task,
79634
- notified: true
79635
- };
79636
- });
79637
- if (!shouldEnqueue) {
79638
- return;
79639
79790
  }
79640
79791
  const escapedDescription = escapeXml(description);
79641
- const summary = status === "completed" ? `Agent "${escapedDescription}" completed` : status === "failed" ? `Agent "${escapedDescription}" failed: ${escapeXml(error || "Unknown error")}` : `Agent "${escapedDescription}" was stopped`;
79792
+ const summary = status === "completed" ? `Agent "${escapedDescription}" completed` : status === "failed" ? `Agent "${escapedDescription}" failed: ${escapeXml(error || "Unknown error")}` : status === "killed" ? `Agent "${escapedDescription}" was stopped` : status === "needs_input" ? `Agent "${escapedDescription}" needs input: ${escapeXml(inputRequest || "Permission request or question pending")}` : `Agent "${escapedDescription}" ${escapeXml(status)}`;
79642
79793
  const outputPath = getTaskOutputPath(taskId);
79643
79794
  const toolUseIdLine = toolUseId ? `
79644
79795
  <${TOOL_USE_ID_TAG}>${escapeXml(toolUseId)}</${TOOL_USE_ID_TAG}>` : "";
@@ -86835,6 +86986,7 @@ async function runHeadless(inputPrompt, options) {
86835
86986
  }
86836
86987
  cronScheduler.stop();
86837
86988
  await drainToOutput();
86989
+ await drainPendingBackgroundAgents(abortController.signal);
86838
86990
  } catch (error) {
86839
86991
  cronScheduler.stop();
86840
86992
  logForDebugging2(headlessErrorLine(error), { level: "error" });
@@ -180233,6 +180385,7 @@ __export(exports_engineCompat, {
180233
180385
  dequeueAllMatching: () => dequeueAllMatching,
180234
180386
  dequeuePendingNotification: () => dequeuePendingNotification,
180235
180387
  doesMessageExistInSession: () => doesMessageExistInSession,
180388
+ drainPendingBackgroundAgents: () => drainPendingBackgroundAgents,
180236
180389
  drainPendingMessages: () => drainPendingMessages,
180237
180390
  drainSdkEvents: () => drainSdkEvents,
180238
180391
  emitTaskTerminatedSdk: () => emitTaskTerminatedSdk,
@@ -180400,6 +180553,7 @@ __export(exports_engineCompat, {
180400
180553
  hasForegroundTasks: () => hasForegroundTasks,
180401
180554
  hasMetInitializationThreshold: () => hasMetInitializationThreshold,
180402
180555
  hasMetUpdateThreshold: () => hasMetUpdateThreshold,
180556
+ hasPendingBackgroundAgents: () => hasPendingBackgroundAgents,
180403
180557
  hasPendingNotifications: () => hasPendingNotifications,
180404
180558
  hasSessionMessagesCache: () => hasSessionMessagesCache,
180405
180559
  hasWorkingInProcessTeammates: () => hasWorkingInProcessTeammates,
@@ -180582,6 +180736,7 @@ __export(exports_engineCompat, {
180582
180736
  renderableSearchText: () => renderableSearchText,
180583
180737
  reportAutoCompactCircuitFailures: () => reportAutoCompactCircuitFailures,
180584
180738
  resetAutoCompactCircuitForTesting: () => resetAutoCompactCircuitForTesting,
180739
+ resetBackgroundAgentTracker: () => resetBackgroundAgentTracker,
180585
180740
  resetBuiltinCommandNamesSourceForTesting: () => resetBuiltinCommandNamesSourceForTesting,
180586
180741
  resetCheckInState: () => resetCheckInState,
180587
180742
  resetCommandQueue: () => resetCommandQueue,
@@ -180621,6 +180776,7 @@ __export(exports_engineCompat, {
180621
180776
  roughTokenCountEstimationForContent: () => roughTokenCountEstimationForContent,
180622
180777
  roughTokenCountEstimationForMessages: () => roughTokenCountEstimationForMessages,
180623
180778
  runAgent: () => runAgent,
180779
+ runAsyncAgentLifecycle: () => runAsyncAgentLifecycle,
180624
180780
  runCleanupFunctions: () => runCleanupFunctions2,
180625
180781
  runHooksStream: () => runHooksStream,
180626
180782
  runPostCompactCleanup: () => runPostCompactCleanup,
@@ -180689,6 +180845,7 @@ __export(exports_engineCompat, {
180689
180845
  tokenCountWithEstimation: () => tokenCountWithEstimation,
180690
180846
  toolResultSearchText: () => toolResultSearchText,
180691
180847
  toolUseSearchText: () => toolUseSearchText,
180848
+ trackBackgroundAgent: () => trackBackgroundAgent,
180692
180849
  truncateHeadForPTLRetry: () => truncateHeadForPTLRetry,
180693
180850
  tryAcquireSchedulerLock: () => tryAcquireSchedulerLock,
180694
180851
  tryReactiveCompact: () => tryReactiveCompact,
@@ -180712,6 +180869,7 @@ __export(exports_engineCompat, {
180712
180869
  waitForSessionMemoryExtraction: () => waitForSessionMemoryExtraction,
180713
180870
  waitForTeammatesToBecomeIdle: () => waitForTeammatesToBecomeIdle,
180714
180871
  worktreeBranchName: () => worktreeBranchName,
180872
+ wrapPermissionGateForBackground: () => wrapPermissionGateForBackground,
180715
180873
  writeCronTasks: () => writeCronTasks,
180716
180874
  writeToMailbox: () => writeToMailbox
180717
180875
  });
@@ -275861,7 +276019,7 @@ function extractPartialResult(messages) {
275861
276019
  }
275862
276020
  return;
275863
276021
  }
275864
- async function runAsyncAgentLifecycle({
276022
+ async function runAsyncAgentLifecycle2({
275865
276023
  taskId,
275866
276024
  abortController,
275867
276025
  makeStream,
@@ -276188,8 +276346,8 @@ ${whenNotToUseSection}
276188
276346
  Usage notes:
276189
276347
  - Always include a short description (3-5 words) summarizing what the agent will do${concurrencyNote}
276190
276348
  - When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.${!isEnvTruthy2(process.env.ATLAS_DISABLE_BACKGROUND_TASKS) && !isInProcessTeammate3() && !forkEnabled ? `
276191
- - You can optionally run agents in the background using the run_in_background parameter. When an agent runs in the background, you will be automatically notified when it completes — do NOT sleep, poll, or proactively check on its progress. Continue with other work or respond to the user instead.
276192
- - **Foreground vs background**: Use foreground (default) when you need the agent's results before you can proceed — e.g., research agents whose findings inform your next steps. Use background when you have genuinely independent work to do in parallel.` : ""}
276349
+ - Agents run in the background by default. When an agent runs in the background, you will be automatically notified when it completes — do NOT sleep, poll, or proactively check on its progress. Continue with other work or respond to the user instead.
276350
+ - **Foreground vs background**: Agents run in the background by default. Use foreground (set run_in_background to false) when you need the agent's results before you can proceed — e.g., research agents whose findings inform your next steps. Use background when you have genuinely independent work to do in parallel.` : ""}
276193
276351
  - To continue a previously spawned agent, use ${SEND_MESSAGE_TOOL_NAME3} with the agent's ID or name as the \`to\` field. The agent resumes with its full context preserved. ${forkEnabled ? "Each fresh Agent invocation with a subagent_type starts without context — provide a complete task description." : "Each Agent invocation starts fresh — provide a complete task description."}
276194
276352
  - The agent's outputs should generally be trusted
276195
276353
  - Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.)${forkEnabled ? "" : ", since it is not aware of the user's intent"}
@@ -276214,6 +276372,15 @@ var init_prompt13 = __esm(() => {
276214
276372
  });
276215
276373
 
276216
276374
  // src/tui/tools/AgentTool/AgentTool.ts
276375
+ function isAgentBackgroundByDefault2() {
276376
+ return !isEnvTruthy2(process.env.ATLAS_AGENT_DEFAULT_FOREGROUND);
276377
+ }
276378
+ function shouldRunInBackground2(runInBg) {
276379
+ if (isAgentBackgroundByDefault2()) {
276380
+ return runInBg !== false;
276381
+ }
276382
+ return !!runInBg;
276383
+ }
276217
276384
  function resolveAgentDefinition2(subagentType, agents) {
276218
276385
  if (!subagentType)
276219
276386
  return GENERAL_PURPOSE_AGENT2;
@@ -276246,6 +276413,7 @@ var init_AgentTool2 = __esm(() => {
276246
276413
  init_prompt13();
276247
276414
  init_runAgent2();
276248
276415
  init_UI9();
276416
+ init_envUtils2();
276249
276417
  inputSchema13 = lazySchema2(() => object({
276250
276418
  description: string2().describe("A short (3-5 word) description of the task"),
276251
276419
  prompt: string2().describe("The task for the agent to perform"),
@@ -276315,7 +276483,7 @@ var init_AgentTool2 = __esm(() => {
276315
276483
  },
276316
276484
  async call(args, context, canUseTool, parentMessage, onProgress) {
276317
276485
  const agents = getBuiltInAgents2();
276318
- const isAsync = !!args.run_in_background;
276486
+ const isAsync = shouldRunInBackground2(args.run_in_background);
276319
276487
  const agentId = createAgentId(args.description);
276320
276488
  const parentModel = context && context.options && (context.options.mainLoopModel || context.options.model) || "small";
276321
276489
  logForDebugging3("[AGENT] launching agent, type=" + (args.subagent_type ?? (isForkSubagentEnabled2() ? "fork" : "general-purpose")));
@@ -311132,7 +311300,7 @@ async function resumeAgentBackground({
311132
311300
  invocationEmitted: false
311133
311301
  };
311134
311302
  const wrapWithCwd = (fn) => resumedWorktreePath ? runWithCwdOverride(resumedWorktreePath, fn) : fn();
311135
- runWithAgentContext(asyncAgentContext, () => wrapWithCwd(() => runAsyncAgentLifecycle({
311303
+ runWithAgentContext(asyncAgentContext, () => wrapWithCwd(() => runAsyncAgentLifecycle2({
311136
311304
  taskId: agentBackgroundTask.agentId,
311137
311305
  abortController: agentBackgroundTask.abortController,
311138
311306
  makeStream: (onCacheSafeParams) => runAgent2({
@@ -321060,6 +321228,10 @@ function buildAgentLoopParams(m) {
321060
321228
  toolUseContext: m.toolUseContext
321061
321229
  }),
321062
321230
  toolContext: m.toolUseContext,
321231
+ hasPendingBackgroundTasks: () => {
321232
+ const tasks = m.toolUseContext?.getAppState?.()?.tasks;
321233
+ return tasks ? hasNonTerminalTasks(tasks) : false;
321234
+ },
321063
321235
  hooks: createLoopHooks({
321064
321236
  options: {
321065
321237
  sessionId: getSessionId(),
@@ -321091,6 +321263,7 @@ function buildAgentLoopParams(m) {
321091
321263
  var init_agentLoopDeps = __esm(() => {
321092
321264
  init_modelprovider2();
321093
321265
  init_engine();
321266
+ init_Task();
321094
321267
  init_settings3();
321095
321268
  init_shared();
321096
321269
  init_bootstrap();
@@ -425283,6 +425456,9 @@ import { randomBytes as randomBytes22 } from "crypto";
425283
425456
  function isTerminalTaskStatus2(status) {
425284
425457
  return status === "completed" || status === "failed" || status === "killed";
425285
425458
  }
425459
+ function hasNonTerminalTasks(tasks) {
425460
+ return Object.values(tasks).some((t) => !isTerminalTaskStatus2(t.status));
425461
+ }
425286
425462
  function getTaskIdPrefix(type) {
425287
425463
  return TASK_ID_PREFIXES[type] ?? "x";
425288
425464
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlasharness/atlascode",
3
- "version": "0.1.64",
3
+ "version": "0.1.66",
4
4
  "description": "AtlasCode \u2014 Coding Agent for the domestic computing ecosystem (Ascend NPU + domestic LLM backends)",
5
5
  "bin": {
6
6
  "atlas": "dist/cli.js",