actoviq-agent-sdk 0.3.0 → 0.3.1

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 (128) hide show
  1. package/dist/src/cli/actoviq-react.js +16 -7
  2. package/dist/src/cli/actoviq-react.js.map +1 -1
  3. package/dist/src/config/anthropicEnvMapping.d.ts +18 -0
  4. package/dist/src/config/anthropicEnvMapping.d.ts.map +1 -0
  5. package/dist/src/config/anthropicEnvMapping.js +40 -0
  6. package/dist/src/config/anthropicEnvMapping.js.map +1 -0
  7. package/dist/src/config/resolveRuntimeConfig.d.ts.map +1 -1
  8. package/dist/src/config/resolveRuntimeConfig.js +37 -13
  9. package/dist/src/config/resolveRuntimeConfig.js.map +1 -1
  10. package/dist/src/index.d.ts +3 -0
  11. package/dist/src/index.d.ts.map +1 -1
  12. package/dist/src/index.js +3 -0
  13. package/dist/src/index.js.map +1 -1
  14. package/dist/src/memory/actoviqMemory.d.ts.map +1 -1
  15. package/dist/src/memory/actoviqMemory.js +10 -6
  16. package/dist/src/memory/actoviqMemory.js.map +1 -1
  17. package/dist/src/memory/actoviqTranscriptLogger.d.ts.map +1 -1
  18. package/dist/src/memory/actoviqTranscriptLogger.js +2 -2
  19. package/dist/src/memory/actoviqTranscriptLogger.js.map +1 -1
  20. package/dist/src/parity/actoviqBridgeEvents.d.ts.map +1 -1
  21. package/dist/src/parity/actoviqBridgeEvents.js +4 -2
  22. package/dist/src/parity/actoviqBridgeEvents.js.map +1 -1
  23. package/dist/src/parity/actoviqBridgeSdk.d.ts.map +1 -1
  24. package/dist/src/parity/actoviqBridgeSdk.js +9 -1
  25. package/dist/src/parity/actoviqBridgeSdk.js.map +1 -1
  26. package/dist/src/parity/actoviqCleanBridgeCompatSdk.d.ts +277 -0
  27. package/dist/src/parity/actoviqCleanBridgeCompatSdk.d.ts.map +1 -0
  28. package/dist/src/parity/actoviqCleanBridgeCompatSdk.js +1391 -0
  29. package/dist/src/parity/actoviqCleanBridgeCompatSdk.js.map +1 -0
  30. package/dist/src/parity/portableSessions.d.ts.map +1 -1
  31. package/dist/src/parity/portableSessions.js +6 -2
  32. package/dist/src/parity/portableSessions.js.map +1 -1
  33. package/dist/src/provider/client.d.ts +3 -0
  34. package/dist/src/provider/client.d.ts.map +1 -1
  35. package/dist/src/provider/client.js +77 -6
  36. package/dist/src/provider/client.js.map +1 -1
  37. package/dist/src/provider/openai-client.d.ts.map +1 -1
  38. package/dist/src/provider/openai-client.js +43 -4
  39. package/dist/src/provider/openai-client.js.map +1 -1
  40. package/dist/src/runtime/actoviqAgents.d.ts +6 -0
  41. package/dist/src/runtime/actoviqAgents.d.ts.map +1 -1
  42. package/dist/src/runtime/actoviqAgents.js +110 -14
  43. package/dist/src/runtime/actoviqAgents.js.map +1 -1
  44. package/dist/src/runtime/actoviqApiMicrocompact.d.ts +14 -0
  45. package/dist/src/runtime/actoviqApiMicrocompact.d.ts.map +1 -1
  46. package/dist/src/runtime/actoviqApiMicrocompact.js +102 -0
  47. package/dist/src/runtime/actoviqApiMicrocompact.js.map +1 -1
  48. package/dist/src/runtime/actoviqBackgroundTasks.d.ts +1 -0
  49. package/dist/src/runtime/actoviqBackgroundTasks.d.ts.map +1 -1
  50. package/dist/src/runtime/actoviqBackgroundTasks.js +1 -0
  51. package/dist/src/runtime/actoviqBackgroundTasks.js.map +1 -1
  52. package/dist/src/runtime/actoviqCompact.d.ts +43 -0
  53. package/dist/src/runtime/actoviqCompact.d.ts.map +1 -1
  54. package/dist/src/runtime/actoviqCompact.js +237 -7
  55. package/dist/src/runtime/actoviqCompact.js.map +1 -1
  56. package/dist/src/runtime/actoviqPermissions.js +18 -18
  57. package/dist/src/runtime/actoviqPermissions.js.map +1 -1
  58. package/dist/src/runtime/agentClient.d.ts +11 -0
  59. package/dist/src/runtime/agentClient.d.ts.map +1 -1
  60. package/dist/src/runtime/agentClient.js +302 -4
  61. package/dist/src/runtime/agentClient.js.map +1 -1
  62. package/dist/src/runtime/conversationEngine.d.ts.map +1 -1
  63. package/dist/src/runtime/conversationEngine.js +496 -36
  64. package/dist/src/runtime/conversationEngine.js.map +1 -1
  65. package/dist/src/runtime/defaultActoviqAgents.d.ts +3 -0
  66. package/dist/src/runtime/defaultActoviqAgents.d.ts.map +1 -0
  67. package/dist/src/runtime/defaultActoviqAgents.js +44 -0
  68. package/dist/src/runtime/defaultActoviqAgents.js.map +1 -0
  69. package/dist/src/runtime/safetyChecks.d.ts.map +1 -1
  70. package/dist/src/runtime/safetyChecks.js +15 -9
  71. package/dist/src/runtime/safetyChecks.js.map +1 -1
  72. package/dist/src/runtime/sessionManager.d.ts.map +1 -1
  73. package/dist/src/runtime/sessionManager.js +10 -5
  74. package/dist/src/runtime/sessionManager.js.map +1 -1
  75. package/dist/src/runtime/tools.d.ts.map +1 -1
  76. package/dist/src/runtime/tools.js +1 -0
  77. package/dist/src/runtime/tools.js.map +1 -1
  78. package/dist/src/scheduling/cron.d.ts.map +1 -1
  79. package/dist/src/scheduling/cron.js +3 -1
  80. package/dist/src/scheduling/cron.js.map +1 -1
  81. package/dist/src/storage/backgroundTaskStore.d.ts.map +1 -1
  82. package/dist/src/storage/backgroundTaskStore.js +3 -2
  83. package/dist/src/storage/backgroundTaskStore.js.map +1 -1
  84. package/dist/src/storage/mailboxStore.d.ts.map +1 -1
  85. package/dist/src/storage/mailboxStore.js +3 -3
  86. package/dist/src/storage/mailboxStore.js.map +1 -1
  87. package/dist/src/storage/pathSafety.d.ts +4 -0
  88. package/dist/src/storage/pathSafety.d.ts.map +1 -0
  89. package/dist/src/storage/pathSafety.js +28 -0
  90. package/dist/src/storage/pathSafety.js.map +1 -0
  91. package/dist/src/storage/sessionStore.d.ts +2 -2
  92. package/dist/src/storage/sessionStore.d.ts.map +1 -1
  93. package/dist/src/storage/sessionStore.js +23 -8
  94. package/dist/src/storage/sessionStore.js.map +1 -1
  95. package/dist/src/storage/teammateStore.d.ts.map +1 -1
  96. package/dist/src/storage/teammateStore.js +3 -2
  97. package/dist/src/storage/teammateStore.js.map +1 -1
  98. package/dist/src/tools/actoviqCoreTools.d.ts +7 -2
  99. package/dist/src/tools/actoviqCoreTools.d.ts.map +1 -1
  100. package/dist/src/tools/actoviqCoreTools.js +2 -2
  101. package/dist/src/tools/actoviqCoreTools.js.map +1 -1
  102. package/dist/src/tools/actoviqFileTools.d.ts.map +1 -1
  103. package/dist/src/tools/actoviqFileTools.js +16 -5
  104. package/dist/src/tools/actoviqFileTools.js.map +1 -1
  105. package/dist/src/tools/actoviqNotebookEdit.d.ts.map +1 -1
  106. package/dist/src/tools/actoviqNotebookEdit.js +121 -4
  107. package/dist/src/tools/actoviqNotebookEdit.js.map +1 -1
  108. package/dist/src/tools/actoviqShellTools.d.ts.map +1 -1
  109. package/dist/src/tools/actoviqShellTools.js +38 -9
  110. package/dist/src/tools/actoviqShellTools.js.map +1 -1
  111. package/dist/src/tools/actoviqWebTools.d.ts.map +1 -1
  112. package/dist/src/tools/actoviqWebTools.js +50 -18
  113. package/dist/src/tools/actoviqWebTools.js.map +1 -1
  114. package/dist/src/tools/bash/BashTool.js +4 -4
  115. package/dist/src/tools/bash/BashTool.js.map +1 -1
  116. package/dist/src/tools/todo/TodoWriteTool.d.ts +14 -0
  117. package/dist/src/tools/todo/TodoWriteTool.d.ts.map +1 -1
  118. package/dist/src/tools/todo/TodoWriteTool.js +45 -2
  119. package/dist/src/tools/todo/TodoWriteTool.js.map +1 -1
  120. package/dist/src/types.d.ts +116 -1
  121. package/dist/src/types.d.ts.map +1 -1
  122. package/dist/src/types.js.map +1 -1
  123. package/dist/src/workflow/workflowEngine.js +26 -3
  124. package/dist/src/workflow/workflowEngine.js.map +1 -1
  125. package/dist/src/workspace/actoviqWorkspace.d.ts.map +1 -1
  126. package/dist/src/workspace/actoviqWorkspace.js +25 -2
  127. package/dist/src/workspace/actoviqWorkspace.js.map +1 -1
  128. package/package.json +25 -1
@@ -1,4 +1,5 @@
1
1
  import path from 'node:path';
2
+ import { z } from 'zod';
2
3
  import { createActoviqBuddyApi } from '../buddy/actoviqBuddy.js';
3
4
  import { createActoviqComputerUseMcpServer, createActoviqComputerUseTools, } from '../computer/actoviqComputerUse.js';
4
5
  import { resolveRuntimeConfig } from '../config/resolveRuntimeConfig.js';
@@ -15,10 +16,12 @@ import { TeammateStore } from '../storage/teammateStore.js';
15
16
  import { ActoviqSwarmApi } from '../swarm/actoviqSwarm.js';
16
17
  import { createActoviqFileTools } from '../tools/actoviqFileTools.js';
17
18
  import { ActoviqAgentsApi, createActoviqTaskTool, summarizeActoviqAgentDefinition, } from './actoviqAgents.js';
19
+ import { getDefaultActoviqAgents } from './defaultActoviqAgents.js';
18
20
  import { ActoviqSkillsApi, loadActoviqSkillDefinitions, resolveActoviqSkillPrompt, summarizeActoviqSkillDefinition, } from './actoviqSkills.js';
19
21
  import { ActoviqBackgroundTaskManager, ActoviqBackgroundTasksApi, } from './actoviqBackgroundTasks.js';
20
22
  import { ActoviqContextApi, ActoviqSlashCommandsApi, } from './actoviqSlashCommands.js';
21
- import { compactActoviqSession, getPersistedActoviqCompactHistory, getPersistedActoviqCompactState, isActoviqPromptTooLongError, } from './actoviqCompact.js';
23
+ import { compactActoviqSession, getPersistedActoviqCompactHistory, getPersistedActoviqCompactState, isActoviqPromptTooLongError, trackRecentFile, trackRecentSkill, } from './actoviqCompact.js';
24
+ const RECENT_FILE_TOOL_NAMES = new Set(['Read', 'Write', 'Edit', 'NotebookEdit']);
22
25
  import { ActoviqToolsApi, buildActoviqCleanToolCatalog, resolveActoviqCleanToolMetadata, } from './actoviqToolCatalog.js';
23
26
  import { WorkflowApi } from '../workflow/workflowBuilder.js';
24
27
  import { SessionManager } from './sessionManager.js';
@@ -29,6 +32,7 @@ import { createOpenaiModelApi } from '../provider/openai-model-api.js';
29
32
  import { AgentRunStream } from './asyncQueue.js';
30
33
  import { executeConversation } from './conversationEngine.js';
31
34
  import { asError, createId, deepClone, isRecord, nowIso, truncateText } from './helpers.js';
35
+ import { tool } from './tools.js';
32
36
  import { buildInvokedSkillMessages, buildRelevantMemoryMessages, extractTextFromContent, } from './messageUtils.js';
33
37
  import { AgentSession } from './agentSession.js';
34
38
  const RELEVANT_MEMORY_SESSION_STATE_KEY = '__actoviqRelevantMemoryState';
@@ -172,12 +176,35 @@ function getAgentContinuityState(metadata) {
172
176
  count: typeof record.count === 'number' ? record.count : 1,
173
177
  lastInvokedAt: record.lastInvokedAt,
174
178
  lastDescription: typeof record.lastDescription === 'string' ? record.lastDescription : undefined,
179
+ lastRunId: typeof record.lastRunId === 'string' ? record.lastRunId : undefined,
180
+ lastSessionId: typeof record.lastSessionId === 'string' ? record.lastSessionId : undefined,
181
+ lastStatus: record.lastStatus === 'completed' || record.lastStatus === 'async_launched'
182
+ ? record.lastStatus
183
+ : undefined,
184
+ lastTaskId: typeof record.lastTaskId === 'string' ? record.lastTaskId : undefined,
185
+ lastTextSummary: typeof record.lastTextSummary === 'string' ? record.lastTextSummary : undefined,
186
+ runIds: readStringArray(record.runIds),
187
+ sessionIds: readStringArray(record.sessionIds),
188
+ taskIds: readStringArray(record.taskIds),
189
+ totalToolCallCount: typeof record.totalToolCallCount === 'number'
190
+ ? record.totalToolCallCount
191
+ : undefined,
192
+ totalToolErrorCount: typeof record.totalToolErrorCount === 'number'
193
+ ? record.totalToolErrorCount
194
+ : undefined,
175
195
  },
176
196
  ];
177
197
  })
178
198
  : [],
179
199
  };
180
200
  }
201
+ function readStringArray(value) {
202
+ if (!Array.isArray(value)) {
203
+ return undefined;
204
+ }
205
+ const values = value.filter((entry) => typeof entry === 'string');
206
+ return values.length > 0 ? values : undefined;
207
+ }
181
208
  function mergeDelegatedAgents(existing, pending) {
182
209
  const merged = new Map(existing.map(record => [record.name, { ...record }]));
183
210
  for (const record of pending) {
@@ -188,15 +215,51 @@ function mergeDelegatedAgents(existing, pending) {
188
215
  count: 1,
189
216
  lastInvokedAt: record.invokedAt,
190
217
  lastDescription: record.description,
218
+ lastRunId: record.runId,
219
+ lastSessionId: record.sessionId,
220
+ lastStatus: record.status,
221
+ lastTaskId: record.taskId,
222
+ lastTextSummary: record.textSummary,
223
+ runIds: record.runId ? [record.runId] : undefined,
224
+ sessionIds: record.sessionId ? [record.sessionId] : undefined,
225
+ taskIds: record.taskId ? [record.taskId] : undefined,
226
+ totalToolCallCount: record.toolCallCount,
227
+ totalToolErrorCount: record.toolErrorCount,
191
228
  });
192
229
  continue;
193
230
  }
194
231
  current.count += 1;
195
232
  current.lastInvokedAt = record.invokedAt;
196
233
  current.lastDescription = record.description ?? current.lastDescription;
234
+ current.lastRunId = record.runId ?? current.lastRunId;
235
+ current.lastSessionId = record.sessionId ?? current.lastSessionId;
236
+ current.lastStatus = record.status ?? current.lastStatus;
237
+ current.lastTaskId = record.taskId ?? current.lastTaskId;
238
+ current.lastTextSummary = record.textSummary ?? current.lastTextSummary;
239
+ current.runIds = appendUnique(current.runIds, record.runId);
240
+ current.sessionIds = appendUnique(current.sessionIds, record.sessionId);
241
+ current.taskIds = appendUnique(current.taskIds, record.taskId);
242
+ current.totalToolCallCount = sumOptional(current.totalToolCallCount, record.toolCallCount);
243
+ current.totalToolErrorCount = sumOptional(current.totalToolErrorCount, record.toolErrorCount);
197
244
  }
198
245
  return [...merged.values()].sort((left, right) => right.lastInvokedAt.localeCompare(left.lastInvokedAt));
199
246
  }
247
+ function appendUnique(existing, value) {
248
+ if (!value) {
249
+ return existing;
250
+ }
251
+ const next = existing ? [...existing] : [];
252
+ if (!next.includes(value)) {
253
+ next.push(value);
254
+ }
255
+ return next;
256
+ }
257
+ function sumOptional(current, next) {
258
+ if (next === undefined) {
259
+ return current;
260
+ }
261
+ return (current ?? 0) + next;
262
+ }
200
263
  function getInvokedSkillState(metadata) {
201
264
  const raw = metadata?.[INVOKED_SKILLS_STATE_KEY];
202
265
  if (!Array.isArray(raw)) {
@@ -359,6 +422,13 @@ export class ActoviqAgentClient {
359
422
  if (!this.defaultTools.some(tool => tool.name === 'Task')) {
360
423
  this.defaultTools.unshift(this.createTaskTool());
361
424
  }
425
+ this.replaceDefaultTool(this.createBackgroundTaskListTool());
426
+ this.replaceDefaultTool(this.createBackgroundTaskGetTool());
427
+ this.replaceDefaultTool(this.createBackgroundTaskStopTool());
428
+ this.replaceDefaultTool(this.createBackgroundTaskOutputTool());
429
+ if (this.listSkillDefinitions().length > 0) {
430
+ this.replaceDefaultTool(this.createSkillRegistryTool());
431
+ }
362
432
  }
363
433
  async listToolMetadata(options) {
364
434
  return resolveActoviqCleanToolMetadata({
@@ -419,6 +489,9 @@ export class ActoviqAgentClient {
419
489
  disableDefaultSkills: options.disableDefaultSkills,
420
490
  loadDefaultSkillDirectories: options.loadDefaultSkillDirectories,
421
491
  });
492
+ const agentDefinitions = options.disableDefaultAgents === true
493
+ ? [...(options.agents ?? [])]
494
+ : [...getDefaultActoviqAgents(), ...(options.agents ?? [])];
422
495
  const defaultTools = [...(options.tools ?? [])];
423
496
  const defaultMcpServers = [...(options.mcpServers ?? [])];
424
497
  if (options.computerUse) {
@@ -430,7 +503,7 @@ export class ActoviqAgentClient {
430
503
  defaultTools.push(...createActoviqComputerUseTools(computerUseOptions));
431
504
  }
432
505
  }
433
- return new ActoviqAgentClient(config, store, backgroundTaskStore, mailboxStore, teammateStore, modelApi, mcpManager, defaultTools, defaultMcpServers, options.hooks, options.agents ?? [], [...loadedSkills, ...(options.skills ?? [])], options.permissionMode, options.permissions, options.classifier, options.approver, options.sessionManager);
506
+ return new ActoviqAgentClient(config, store, backgroundTaskStore, mailboxStore, teammateStore, modelApi, mcpManager, defaultTools, defaultMcpServers, options.hooks, agentDefinitions, [...loadedSkills, ...(options.skills ?? [])], options.permissionMode, options.permissions, options.classifier, options.approver, options.sessionManager);
434
507
  }
435
508
  async run(input, options = {}) {
436
509
  const runId = createId();
@@ -492,6 +565,7 @@ export class ActoviqAgentClient {
492
565
  }
493
566
  async createSession(options = {}) {
494
567
  const stored = await this.store.create({
568
+ id: options.id,
495
569
  title: options.title,
496
570
  systemPrompt: options.systemPrompt ?? this.config.systemPrompt,
497
571
  model: options.model ?? this.config.model,
@@ -529,6 +603,7 @@ export class ActoviqAgentClient {
529
603
  return this.dream.maybeAutoDream(options);
530
604
  }
531
605
  async close() {
606
+ this.sessionManager.dispose();
532
607
  await this.mcpManager.closeAll();
533
608
  }
534
609
  listAgentDefinitions() {
@@ -588,18 +663,189 @@ export class ActoviqAgentClient {
588
663
  createTaskTool(options = {}) {
589
664
  return createActoviqTaskTool({
590
665
  ...options,
666
+ listAgentDefinitions: () => this.listAgentDefinitions(),
591
667
  getAgentDefinition: (agent) => this.getAgentDefinition(agent),
592
668
  runAgent: (agent, prompt, runOptions) => this.runWithAgent(agent, prompt, runOptions),
593
- onDelegated: ({ subagentType, description, parentSessionId, parentRunId }) => {
669
+ onDelegated: ({ subagentType, description, parentSessionId, parentRunId, runId, sessionId, status, taskId, toolCallCount, toolErrorCount, textSummary, }) => {
594
670
  this.recordPendingDelegation(parentSessionId ?? parentRunId, {
595
671
  name: subagentType,
596
672
  description,
597
673
  invokedAt: nowIso(),
674
+ runId,
675
+ sessionId,
676
+ status,
677
+ taskId,
678
+ toolCallCount,
679
+ toolErrorCount,
680
+ textSummary,
598
681
  });
599
682
  },
600
683
  launchBackgroundAgent: (agent, prompt, backgroundOptions, runOptions) => this.launchBackgroundAgentTask(agent, prompt, backgroundOptions, runOptions),
601
684
  });
602
685
  }
686
+ replaceDefaultTool(replacement) {
687
+ const existingIndex = this.defaultTools.findIndex(tool => tool.name === replacement.name);
688
+ if (existingIndex >= 0) {
689
+ this.defaultTools.splice(existingIndex, 1, replacement);
690
+ return;
691
+ }
692
+ this.defaultTools.push(replacement);
693
+ }
694
+ /**
695
+ * Model-facing Skill tool backed by the real skill registry. Loads the
696
+ * resolved skill content into the conversation as the tool result
697
+ * (progressive disclosure), instead of the former no-op stub.
698
+ */
699
+ createSkillRegistryTool() {
700
+ return tool({
701
+ name: 'Skill',
702
+ description: 'Load a registered skill by name. The skill content (workflow, checklist, or domain knowledge) is returned so you can follow it for the current task.',
703
+ inputSchema: z.strictObject({
704
+ skill: z.string().describe('The name of the skill to load'),
705
+ args: z.string().optional().describe('Optional arguments for the skill'),
706
+ }),
707
+ isReadOnly: () => true,
708
+ prompt: () => {
709
+ const names = this.listSkillDefinitions()
710
+ .filter((definition) => definition.disableModelInvocation !== true)
711
+ .map((definition) => definition.description
712
+ ? `- ${definition.name}: ${definition.description}`
713
+ : `- ${definition.name}`);
714
+ if (names.length === 0) {
715
+ return '';
716
+ }
717
+ return [
718
+ 'Use the Skill tool to load a registered skill when the task matches its description.',
719
+ 'Available skills:',
720
+ ...names,
721
+ ].join('\n');
722
+ },
723
+ }, async ({ skill, args }, context) => {
724
+ const definition = this.getSkillDefinition(skill);
725
+ if (!definition || definition.disableModelInvocation === true) {
726
+ const available = this.listSkillDefinitions()
727
+ .filter((entry) => entry.disableModelInvocation !== true)
728
+ .map((entry) => entry.name)
729
+ .join(', ');
730
+ throw new Error(`No skill named "${skill}" is registered.${available ? ` Available skills: ${available}.` : ''}`);
731
+ }
732
+ const resolved = await resolveActoviqSkillPrompt(definition, args ?? '', {
733
+ args: args ?? '',
734
+ workDir: this.config.workDir,
735
+ homeDir: this.config.homeDir,
736
+ sessionId: context.sessionId,
737
+ userId: this.config.userId,
738
+ });
739
+ const content = extractTextFromContent(resolved.content);
740
+ return [
741
+ `Loaded skill "${definition.name}".`,
742
+ '',
743
+ '<skill-content>',
744
+ content,
745
+ '</skill-content>',
746
+ '',
747
+ 'Apply this skill to the current task now.',
748
+ ].join('\n');
749
+ });
750
+ }
751
+ createBackgroundTaskListTool() {
752
+ return tool({
753
+ name: 'TaskList',
754
+ description: 'List background subagent tasks for the current SDK runtime.',
755
+ inputSchema: z.strictObject({}),
756
+ isReadOnly: () => true,
757
+ serialize: (output) => {
758
+ if (output.tasks.length === 0) {
759
+ return 'No background tasks.';
760
+ }
761
+ return output.tasks
762
+ .map(task => [
763
+ `Task id: ${task.id}`,
764
+ `Status: ${task.status}`,
765
+ `Subagent: ${task.subagentType}`,
766
+ `Description: ${task.description}`,
767
+ task.runId ? `Run id: ${task.runId}` : undefined,
768
+ task.sessionId ? `Session id: ${task.sessionId}` : undefined,
769
+ task.completedAt ? `Completed at: ${task.completedAt}` : undefined,
770
+ ].filter(Boolean).join('\n'))
771
+ .join('\n\n');
772
+ },
773
+ }, async () => ({
774
+ tasks: await this.backgroundTaskManager.list(),
775
+ }));
776
+ }
777
+ createBackgroundTaskGetTool() {
778
+ return tool({
779
+ name: 'TaskGet',
780
+ description: 'Retrieve background subagent task status by ID.',
781
+ inputSchema: z.strictObject({
782
+ taskId: z.string().optional().describe('The ID of the task to get'),
783
+ task_id: z.string().optional().describe('The ID of the task to get'),
784
+ }).superRefine((input, ctx) => {
785
+ if (!resolveTaskId(input)) {
786
+ ctx.addIssue({
787
+ code: 'custom',
788
+ path: ['task_id'],
789
+ message: 'Provide `task_id` or `taskId`.',
790
+ });
791
+ }
792
+ }),
793
+ isReadOnly: () => true,
794
+ serialize: serializeBackgroundTaskOutput,
795
+ }, async (input) => {
796
+ const taskId = resolveTaskId(input);
797
+ if (!taskId) {
798
+ throw new Error('TaskGet requires `task_id` or `taskId`.');
799
+ }
800
+ const task = await this.backgroundTaskManager.get(taskId);
801
+ if (!task) {
802
+ throw new Error(`No background task with id "${taskId}" exists.`);
803
+ }
804
+ return task;
805
+ });
806
+ }
807
+ createBackgroundTaskStopTool() {
808
+ return tool({
809
+ name: 'TaskStop',
810
+ description: 'Stop a running background subagent task.',
811
+ inputSchema: z.strictObject({
812
+ task_id: z.string().describe('The ID of the task to stop'),
813
+ }),
814
+ isConcurrencySafe: () => true,
815
+ serialize: serializeBackgroundTaskOutput,
816
+ }, async ({ task_id }) => {
817
+ const task = await this.backgroundTaskManager.cancel(task_id);
818
+ if (!task) {
819
+ throw new Error(`No background task with id "${task_id}" exists.`);
820
+ }
821
+ return task;
822
+ });
823
+ }
824
+ createBackgroundTaskOutputTool() {
825
+ return tool({
826
+ name: 'TaskOutput',
827
+ description: 'Retrieve output from a completed or running background subagent task.',
828
+ inputSchema: z.strictObject({
829
+ task_id: z.string().describe('The ID of the task to get output for'),
830
+ block: z.boolean().optional().describe('Wait for task to complete before returning'),
831
+ timeout: z.number().int().positive().optional().describe('Max wait time in milliseconds'),
832
+ }),
833
+ isReadOnly: () => true,
834
+ serialize: serializeBackgroundTaskOutput,
835
+ }, async ({ task_id, block, timeout }, context) => {
836
+ if (block) {
837
+ return this.backgroundTaskManager.wait(task_id, {
838
+ timeoutMs: timeout,
839
+ signal: context.signal,
840
+ });
841
+ }
842
+ const task = await this.backgroundTaskManager.get(task_id);
843
+ if (!task) {
844
+ throw new Error(`No background task with id "${task_id}" exists.`);
845
+ }
846
+ return task;
847
+ });
848
+ }
603
849
  async prepareSkillExecution(skillName, args, options, sessionId) {
604
850
  const definition = this.requireSkillDefinition(skillName);
605
851
  const resolved = await resolveActoviqSkillPrompt(definition, args, {
@@ -893,6 +1139,12 @@ export class ActoviqAgentClient {
893
1139
  permissionMode: options.permissionMode ?? this.defaultPermissionMode,
894
1140
  });
895
1141
  const systemPrompt = await this.resolveSystemPrompt(options, session, [...(augmentations?.systemPromptParts ?? []), ...toolPromptParts]);
1142
+ const runtimeConfig = options.__actoviqMaxToolIterations
1143
+ ? {
1144
+ ...this.config,
1145
+ maxToolIterations: options.__actoviqMaxToolIterations,
1146
+ }
1147
+ : this.config;
896
1148
  return executeConversation({
897
1149
  runId,
898
1150
  input,
@@ -919,7 +1171,7 @@ export class ActoviqAgentClient {
919
1171
  emit,
920
1172
  skipRunStartedEvent,
921
1173
  modelApi: this.modelApi,
922
- config: this.config,
1174
+ config: runtimeConfig,
923
1175
  mcpManager: this.mcpManager,
924
1176
  }).then(result => ({
925
1177
  ...result,
@@ -1245,6 +1497,7 @@ export class ActoviqAgentClient {
1245
1497
  model: result.model,
1246
1498
  text: result.text,
1247
1499
  toolCallCount: result.toolCalls.length,
1500
+ toolErrorCount: result.toolCalls.filter(call => call.isError).length,
1248
1501
  };
1249
1502
  },
1250
1503
  });
@@ -1279,6 +1532,7 @@ export class ActoviqAgentClient {
1279
1532
  model: result.model,
1280
1533
  text: result.text,
1281
1534
  toolCallCount: result.toolCalls.length,
1535
+ toolErrorCount: result.toolCalls.filter(call => call.isError).length,
1282
1536
  };
1283
1537
  },
1284
1538
  });
@@ -1575,6 +1829,30 @@ export class ActoviqAgentClient {
1575
1829
  next.metadata[INVOKED_SKILLS_STATE_KEY] = invokedSkills;
1576
1830
  result.invokedSkills = invokedSkills;
1577
1831
  }
1832
+ // Track recently touched files and skills so post-compact context
1833
+ // reminders can point the model back to its working set.
1834
+ for (const call of result.toolCalls) {
1835
+ if (call.isError) {
1836
+ continue;
1837
+ }
1838
+ const callInput = call.input;
1839
+ if (RECENT_FILE_TOOL_NAMES.has(call.publicName)) {
1840
+ const filePath = typeof callInput?.file_path === 'string'
1841
+ ? callInput.file_path
1842
+ : typeof callInput?.notebook_path === 'string'
1843
+ ? callInput.notebook_path
1844
+ : undefined;
1845
+ if (filePath) {
1846
+ trackRecentFile(next, filePath);
1847
+ }
1848
+ }
1849
+ if (call.publicName === 'Skill' && typeof callInput?.skill === 'string') {
1850
+ trackRecentSkill(next, callInput.skill);
1851
+ }
1852
+ }
1853
+ for (const record of result.invokedSkills ?? []) {
1854
+ trackRecentSkill(next, record.name);
1855
+ }
1578
1856
  const previousRelevantMemoryState = getRelevantMemorySessionState(next.metadata);
1579
1857
  const surfacedPaths = new Set(previousRelevantMemoryState.surfacedPaths);
1580
1858
  let totalBytes = previousRelevantMemoryState.totalBytes;
@@ -1688,6 +1966,7 @@ export class ActoviqAgentClient {
1688
1966
  mcpServers: [...(definition.mcpServers ?? []), ...(options.mcpServers ?? [])],
1689
1967
  __actoviqUseDefaultTools: definition.inheritDefaultTools !== false,
1690
1968
  __actoviqUseDefaultMcpServers: definition.inheritDefaultMcpServers !== false,
1969
+ __actoviqMaxToolIterations: definition.maxToolIterations,
1691
1970
  };
1692
1971
  }
1693
1972
  mergeSkillRunOptions(definition, options) {
@@ -1719,6 +1998,25 @@ export class ActoviqAgentClient {
1719
1998
  export async function createAgentSdk(options = {}) {
1720
1999
  return ActoviqAgentClient.create(options);
1721
2000
  }
2001
+ function resolveTaskId(input) {
2002
+ return [input.task_id, input.taskId]
2003
+ .map(value => value?.trim())
2004
+ .find((value) => Boolean(value));
2005
+ }
2006
+ function serializeBackgroundTaskOutput(task) {
2007
+ return [
2008
+ `Task id: ${task.id}`,
2009
+ `Status: ${task.status}`,
2010
+ `Subagent: ${task.subagentType}`,
2011
+ task.runId ? `Run id: ${task.runId}` : undefined,
2012
+ task.sessionId ? `Session id: ${task.sessionId}` : undefined,
2013
+ task.model ? `Model: ${task.model}` : undefined,
2014
+ typeof task.toolCallCount === 'number' ? `Tool calls: ${task.toolCallCount}` : undefined,
2015
+ typeof task.toolErrorCount === 'number' ? `Tool errors: ${task.toolErrorCount}` : undefined,
2016
+ task.error ? `Error:\n${task.error}` : undefined,
2017
+ task.text ? `Output:\n${task.text}` : 'Output: <not available yet>',
2018
+ ].filter(Boolean).join('\n');
2019
+ }
1722
2020
  function joinPromptParts(...parts) {
1723
2021
  const normalized = parts.filter((value) => typeof value === 'string' && value.trim().length > 0);
1724
2022
  if (normalized.length === 0) {