@defai.digital/ax-cli 4.1.11 → 4.1.14

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 (83) hide show
  1. package/.ax-cli/settings.json +1 -0
  2. package/README.md +140 -589
  3. package/dist/agent/dependency-resolver.d.ts +7 -0
  4. package/dist/agent/dependency-resolver.js +46 -18
  5. package/dist/agent/dependency-resolver.js.map +1 -1
  6. package/dist/agent/execution/tool-executor.d.ts +4 -0
  7. package/dist/agent/execution/tool-executor.js +76 -52
  8. package/dist/agent/execution/tool-executor.js.map +1 -1
  9. package/dist/agent/parallel-tools.d.ts +4 -0
  10. package/dist/agent/parallel-tools.js +65 -24
  11. package/dist/agent/parallel-tools.js.map +1 -1
  12. package/dist/agent/planning/plan-executor.d.ts +0 -5
  13. package/dist/agent/planning/plan-executor.js +23 -6
  14. package/dist/agent/planning/plan-executor.js.map +1 -1
  15. package/dist/agent/streaming/stream-handler.js +7 -4
  16. package/dist/agent/streaming/stream-handler.js.map +1 -1
  17. package/dist/agent/subagent-orchestrator.d.ts +35 -2
  18. package/dist/agent/subagent-orchestrator.js +188 -146
  19. package/dist/agent/subagent-orchestrator.js.map +1 -1
  20. package/dist/agent/subagent-types.js +3 -1
  21. package/dist/agent/subagent-types.js.map +1 -1
  22. package/dist/agent/subagent.d.ts +15 -4
  23. package/dist/agent/subagent.js +91 -72
  24. package/dist/agent/subagent.js.map +1 -1
  25. package/dist/design/figma-alias.d.ts +77 -0
  26. package/dist/design/figma-alias.js +246 -0
  27. package/dist/design/figma-alias.js.map +1 -1
  28. package/dist/design/figma-client.d.ts +4 -0
  29. package/dist/design/figma-client.js +24 -4
  30. package/dist/design/figma-client.js.map +1 -1
  31. package/dist/design/figma-map.js +78 -6
  32. package/dist/design/figma-map.js.map +1 -1
  33. package/dist/design/figma-tokens.js +6 -2
  34. package/dist/design/figma-tokens.js.map +1 -1
  35. package/dist/design/index.d.ts +1 -1
  36. package/dist/design/index.js +3 -1
  37. package/dist/design/index.js.map +1 -1
  38. package/dist/design/types.d.ts +9 -0
  39. package/dist/mcp/client-v2.js +4 -0
  40. package/dist/mcp/client-v2.js.map +1 -1
  41. package/dist/mcp/config-detector.js +3 -4
  42. package/dist/mcp/config-detector.js.map +1 -1
  43. package/dist/mcp/debug.d.ts +207 -0
  44. package/dist/mcp/debug.js +398 -0
  45. package/dist/mcp/debug.js.map +1 -0
  46. package/dist/mcp/index.d.ts +1 -0
  47. package/dist/mcp/index.js +4 -0
  48. package/dist/mcp/index.js.map +1 -1
  49. package/dist/mcp/reconnection.js +6 -3
  50. package/dist/mcp/reconnection.js.map +1 -1
  51. package/dist/mcp/validation.js +15 -6
  52. package/dist/mcp/validation.js.map +1 -1
  53. package/dist/memory/index.d.ts +1 -0
  54. package/dist/memory/index.js +2 -0
  55. package/dist/memory/index.js.map +1 -1
  56. package/dist/memory/provider-context-store.d.ts +127 -0
  57. package/dist/memory/provider-context-store.js +385 -0
  58. package/dist/memory/provider-context-store.js.map +1 -0
  59. package/dist/sdk/errors.d.ts +2 -0
  60. package/dist/sdk/errors.js +2 -0
  61. package/dist/sdk/errors.js.map +1 -1
  62. package/dist/sdk/index.d.ts +633 -62
  63. package/dist/sdk/index.js +854 -116
  64. package/dist/sdk/index.js.map +1 -1
  65. package/dist/sdk/testing.d.ts +46 -4
  66. package/dist/sdk/testing.js +58 -6
  67. package/dist/sdk/testing.js.map +1 -1
  68. package/dist/sdk/version.d.ts +13 -9
  69. package/dist/sdk/version.js +13 -9
  70. package/dist/sdk/version.js.map +1 -1
  71. package/dist/utils/file-lock.d.ts +141 -0
  72. package/dist/utils/file-lock.js +559 -0
  73. package/dist/utils/file-lock.js.map +1 -0
  74. package/dist/utils/provider-context.d.ts +243 -0
  75. package/dist/utils/provider-context.js +421 -0
  76. package/dist/utils/provider-context.js.map +1 -0
  77. package/dist/utils/provider-file-cache.d.ts +91 -0
  78. package/dist/utils/provider-file-cache.js +165 -0
  79. package/dist/utils/provider-file-cache.js.map +1 -0
  80. package/dist/utils/provider-settings.d.ts +181 -0
  81. package/dist/utils/provider-settings.js +450 -0
  82. package/dist/utils/provider-settings.js.map +1 -0
  83. package/package.json +2 -2
package/dist/sdk/index.js CHANGED
@@ -1,54 +1,116 @@
1
1
  /**
2
- * AX CLI SDK - Programmatic API for AX CLI
2
+ * AX CLI SDK v1.4.0 - Programmatic API for AX CLI
3
3
  *
4
- * This SDK allows you to use AX CLI as a library instead of spawning CLI processes.
5
- * Perfect for integrations, VSCode extensions, and programmatic AI agent usage.
4
+ * Use AX CLI as a library for integrations, VSCode extensions, and programmatic AI agents.
5
+ *
6
+ * ## Installation
7
+ *
8
+ * ```bash
9
+ * npm install @defai.digital/ax-cli
10
+ * ```
6
11
  *
7
12
  * ## Quick Start
8
13
  *
9
- * 1. Run `ax-cli setup` to configure credentials (one-time setup)
10
- * 2. Use the SDK in your code
14
+ * ```typescript
15
+ * import { createAgent, createGLMAgent, createGrokAgent } from '@defai.digital/ax-cli/sdk';
16
+ *
17
+ * // Option 1: Auto-detect provider
18
+ * const agent = await createAgent();
19
+ *
20
+ * // Option 2: Explicit provider
21
+ * const glmAgent = await createGLMAgent(); // Uses ~/.ax-glm/config.json
22
+ * const grokAgent = await createGrokAgent(); // Uses ~/.ax-grok/config.json
23
+ *
24
+ * // Process messages
25
+ * const result = await agent.processUserMessage('Analyze this code');
26
+ * agent.dispose();
27
+ * ```
28
+ *
29
+ * ## Public API (v1.4.0)
30
+ *
31
+ * ### Agent Creation
32
+ * - `createAgent(options?)` - Create agent with auto-detected or specified provider
33
+ * - `createGLMAgent(options?)` - Create GLM (Z.AI) agent
34
+ * - `createGrokAgent(options?)` - Create Grok (xAI) agent
35
+ * - `tryCreateAgent(options?)` - Create agent without throwing (returns result object)
36
+ * - `withAgent(fn, options?)` - Run function with auto-disposed agent
37
+ *
38
+ * ### Error Handling
39
+ * - `SDKError` - Structured error class with error codes
40
+ * - `SDKErrorCode` - Error code enum (SETUP_NOT_RUN, API_KEY_MISSING, etc.)
41
+ *
42
+ * ### Agent Utilities
43
+ * - `getAgentInfo(agent)` - Get provider, model, config info
44
+ * - `getAgentStatus(agent)` - Check if agent is available/busy/disposed
45
+ * - `isAgentDisposed(agent)` - Check disposal state
46
+ * - `disposeAsync(agent)` - Dispose with async hook support
47
+ *
48
+ * ### Provider Utilities
49
+ * - `detectProvider()` - Auto-detect configured provider
50
+ * - `checkProviderHealth(provider?)` - Check if provider is configured
51
+ * - `getAllProviderHealth()` - Check all providers
52
+ *
53
+ * ### Version Info
54
+ * - `SDK_VERSION`, `CLI_VERSION` - Version constants
55
+ * - `getSDKVersion()`, `getCLIVersion()` - Version strings
56
+ * - `isSDKVersionCompatible(minVersion)` - Version check
57
+ *
58
+ * ### Testing
59
+ * - `createMockAgent(responses)` - Create mock for testing
60
+ * - `createMockSettings(overrides)` - Mock settings manager
61
+ *
62
+ * ## Example: Streaming Responses
11
63
  *
12
- * @example
13
64
  * ```typescript
14
- * import { createAgent, SDKError, SDKErrorCode } from '@defai.digital/ax-cli/sdk';
65
+ * import { createGLMAgent, SDKError, SDKErrorCode } from '@defai.digital/ax-cli/sdk';
15
66
  *
16
- * // Create agent (credentials from ax-cli setup)
17
- * const agent = await createAgent({
18
- * maxToolRounds: 50 // Optional: 1-1000, default 400
67
+ * const agent = await createGLMAgent();
68
+ *
69
+ * agent.on('stream', (chunk) => {
70
+ * if (chunk.type === 'content') {
71
+ * process.stdout.write(chunk.content);
72
+ * }
19
73
  * });
20
74
  *
21
75
  * try {
22
- * // Listen to streaming responses
23
- * agent.on('stream', (chunk) => {
24
- * if (chunk.type === 'content') {
25
- * console.log(chunk.content);
26
- * }
27
- * });
28
- *
29
- * // Process messages
30
- * const result = await agent.processUserMessage('List all TypeScript files');
31
- * console.log('Done!', result.length, 'messages');
76
+ * await agent.processUserMessage('Explain async/await');
32
77
  * } catch (error) {
33
- * // Handle structured errors
34
78
  * if (SDKError.isSDKError(error)) {
35
- * if (error.code === SDKErrorCode.SETUP_NOT_RUN) {
36
- * console.error('Please run: ax-cli setup');
37
- * }
79
+ * console.error(`Error [${error.code}]: ${error.message}`);
38
80
  * }
39
81
  * } finally {
40
- * // Always cleanup resources
41
82
  * agent.dispose();
42
83
  * }
43
84
  * ```
44
85
  *
45
- * ## Testing
86
+ * ## Example: Parallel Providers
87
+ *
88
+ * ```typescript
89
+ * import { createGLMAgent, createGrokAgent } from '@defai.digital/ax-cli/sdk';
90
+ *
91
+ * // Run GLM and Grok in parallel
92
+ * const [glm, grok] = await Promise.all([
93
+ * createGLMAgent(),
94
+ * createGrokAgent(),
95
+ * ]);
96
+ *
97
+ * const [glmResult, grokResult] = await Promise.all([
98
+ * glm.processUserMessage('Analyze with GLM'),
99
+ * grok.processUserMessage('Analyze with Grok'),
100
+ * ]);
101
+ *
102
+ * glm.dispose();
103
+ * grok.dispose();
104
+ * ```
105
+ *
106
+ * ## Example: Testing
46
107
  *
47
108
  * ```typescript
48
- * import { createMockAgent } from '@defai.digital/ax-cli/sdk/testing';
109
+ * import { createMockAgent } from '@defai.digital/ax-cli/sdk';
49
110
  *
50
- * const mockAgent = createMockAgent(['Response 1', 'Response 2']);
51
- * const result = await mockAgent.processUserMessage('Test');
111
+ * const mock = createMockAgent(['Hello!', 'How can I help?']);
112
+ * const result = await mock.processUserMessage('Hi');
113
+ * expect(result).toContain('Hello!');
52
114
  * ```
53
115
  *
54
116
  * @packageDocumentation
@@ -63,80 +125,36 @@ export { ContextManager } from '../agent/context-manager.js';
63
125
  // Internal imports for SDK functions
64
126
  import { LLMAgent } from '../agent/llm-agent.js';
65
127
  import { Subagent } from '../agent/subagent.js';
66
- import { getSettingsManager } from '../utils/settings-manager.js';
67
128
  import { initializeMCPServers } from '../llm/tools.js';
68
129
  import { z } from 'zod';
69
130
  import { SDKError, SDKErrorCode } from './errors.js';
131
+ // Provider-aware imports
132
+ import { ProviderContext, detectProvider, PROVIDER_CONFIGS, } from '../utils/provider-context.js';
133
+ import { ProviderSettingsManager, } from '../utils/provider-settings.js';
134
+ // File locking utilities - re-exported for SDK users
135
+ export { withFileLock, withFileLockSync, SafeJsonFile, LockGuard, cleanupStaleLocks, } from '../utils/file-lock.js';
70
136
  // ============================================================================
71
137
  // LLM Client
72
138
  // ============================================================================
73
139
  export { LLMClient } from '../llm/client.js';
74
140
  export { SubagentRole, SubagentState, } from '../agent/subagent-types.js';
75
141
  // ============================================================================
76
- // Settings and Configuration
77
- // ============================================================================
78
- export { getSettingsManager } from '../utils/settings-manager.js';
142
+ // NOTE: Internal utilities removed in SDK v1.4.0 to reduce API surface
79
143
  // ============================================================================
80
- // Utilities
81
- // ============================================================================
82
- export { createTokenCounter } from '../utils/token-counter.js';
83
- export { loadCustomInstructions } from '../utils/custom-instructions.js';
84
- export { buildSystemPrompt } from '../utils/prompt-builder.js';
85
- export { getUsageTracker } from '../utils/usage-tracker.js';
86
- export { extractErrorMessage, createErrorMessage, ErrorCategory } from '../utils/error-handler.js';
87
- // ============================================================================
88
- // MCP Integration
89
- // ============================================================================
90
- export { loadMCPConfig } from '../mcp/config.js';
91
- export { getMCPManager, initializeMCPServers, getMcpConnectionCount, getMCPConnectionStatus, getMCPPrompts, discoverMCPPrompts, getMCPResources, } from '../llm/tools.js';
92
- export { MCPManager } from '../mcp/client.js';
93
- // MCP v2 API (recommended for better type safety)
94
- export { MCPManagerV2, createServerName, createToolName, } from '../mcp/client-v2.js';
95
- // MCP Prompt utilities
96
- export { promptToSlashCommand, parsePromptCommand, formatPromptResult, getPromptDescription, } from '../mcp/prompts.js';
97
- // MCP Resource utilities
98
- export { listAllResources, getResourceContent, parseMCPReference, extractMCPReferences, resolveMCPReferences, searchResources, } from '../mcp/resources.js';
99
- // Z.AI MCP Integration
100
- export {
101
- // Server configuration
102
- ZAI_SERVER_NAMES, ZAI_ENDPOINTS, ZAI_VISION_PACKAGE, ZAI_MCP_TEMPLATES, ZAI_QUOTA_LIMITS, generateZAIServerConfig, getAllZAIServerNames, isZAIServer, getZAITemplate, } from '../mcp/zai-templates.js';
103
- export {
104
- // Detection and status
105
- detectZAIServices, getEnabledZAIServers, validateZAIApiKey, getZAIApiKey, isZAIMCPConfigured, getRecommendedServers, isGLMModel, isZAIBaseURL, formatZAIStatus, } from '../mcp/zai-detector.js';
106
- // Permission system
107
- export { getPermissionManager, initializePermissionManager, PermissionManager, PermissionTier, } from '../permissions/permission-manager.js';
108
- // ============================================================================
109
- // Planning System
110
- // ============================================================================
111
- export { getTaskPlanner, isComplexRequest } from '../planner/index.js';
112
- // ============================================================================
113
- // Checkpoint System
114
- // ============================================================================
115
- export { getCheckpointManager } from '../checkpoint/index.js';
116
- // ============================================================================
117
- // Memory and Context Cache
118
- // ============================================================================
119
- export { ContextStore, getContextStore, resetDefaultStore } from '../memory/context-store.js';
120
- // ============================================================================
121
- // Progress Reporting
122
- // ============================================================================
123
- export { ProgressReporter, getProgressReporter, ProgressEventType } from './progress-reporter.js';
124
- // ============================================================================
125
- // Unified Logging (Phase 3)
126
- // ============================================================================
127
- export { UnifiedLogger, getUnifiedLogger, LogLevel, parseLogLevel, getLogLevelName } from './unified-logger.js';
128
- // ============================================================================
129
- // Shared Tool Registry (Phase 3 - AutomatosX Integration)
130
- // ============================================================================
131
- export { ToolRegistry, getToolRegistry, registerTools, createToolExecutor } from './tool-registry.js';
132
- // ============================================================================
133
- // Internal Tool Registry (Phase 2 - Task 5)
134
- // ============================================================================
135
- export { ToolRegistry as InternalToolRegistry } from '../tools/registry.js';
136
- // ============================================================================
137
- // Constants
138
- // ============================================================================
139
- export { GLM_MODELS, DEFAULT_MODEL, AGENT_CONFIG, PLANNER_CONFIG, VerbosityLevel, UI_CONFIG, } from '../constants.js';
144
+ // The following were intentionally removed from public exports:
145
+ // - Settings utilities (getSettingsManager, createTokenCounter, etc.)
146
+ // - MCP internals (MCPManager, MCPManagerV2, etc.) - use createAgent() instead
147
+ // - Z.AI MCP templates/detector - internal implementation details
148
+ // - Permission system internals
149
+ // - Planning system internals
150
+ // - Checkpoint system internals
151
+ // - Memory/Context internals
152
+ // - Progress reporting
153
+ // - Unified logging
154
+ // - Tool registry internals
155
+ //
156
+ // If you need these, import directly from the specific modules.
157
+ // The SDK public API focuses on: createAgent, createGLMAgent, createGrokAgent, SDKError
140
158
  // ============================================================================
141
159
  // SDK Version (Phase 1.5: Best Practices)
142
160
  // ============================================================================
@@ -149,14 +167,17 @@ export { SDKError, SDKErrorCode } from './errors.js';
149
167
  // Testing Utilities (Phase 1: Best Practices)
150
168
  // ============================================================================
151
169
  export { MockAgent, createMockAgent, MockSettingsManager, createMockSettings, MockMCPServer, createMockMCPServer, waitForAgent, createMockToolResult, assertToolSuccess, assertToolFailure } from './testing.js';
152
- // ============================================================================
153
- // SDK Helper Functions
154
- // ============================================================================
170
+ // Re-export detectProvider for advanced users who need provider detection
171
+ export { detectProvider } from '../utils/provider-context.js';
172
+ // Note: Internal utilities (withFileLock, SafeJsonFile, ProviderFileCache,
173
+ // ProviderContextStore, etc.) are intentionally NOT exported.
174
+ // These are implementation details, not part of the public SDK API.
155
175
  /**
156
176
  * Validation schema for agent options
157
177
  * @internal
158
178
  */
159
179
  const AgentOptionsSchema = z.object({
180
+ provider: z.enum(['glm', 'grok', 'generic']).optional(),
160
181
  maxToolRounds: z.number().int().min(1).max(1000).optional(),
161
182
  debug: z.boolean().optional(),
162
183
  autoCleanup: z.boolean().optional(),
@@ -176,6 +197,7 @@ const AgentOptionsSchema = z.object({
176
197
  * @throws {SDKError} With code SETUP_NOT_RUN if ax-cli setup has not been run
177
198
  * @throws {SDKError} With code API_KEY_MISSING if API key not configured
178
199
  * @throws {SDKError} With code BASE_URL_MISSING if base URL not configured
200
+ * @throws {SDKError} With code MODEL_MISSING if model not configured
179
201
  * @throws {SDKError} With code VALIDATION_ERROR if options are invalid
180
202
  *
181
203
  * @example
@@ -224,24 +246,40 @@ export async function createAgent(options = {}) {
224
246
  catch (error) {
225
247
  throw new SDKError(SDKErrorCode.VALIDATION_ERROR, `Invalid agent options: ${error instanceof Error ? error.message : 'Unknown validation error'}`, error instanceof Error ? error : undefined);
226
248
  }
227
- const settingsManager = getSettingsManager();
228
- // Load settings from ax-cli setup
249
+ // Determine provider (explicit > auto-detect)
250
+ const provider = validated.provider ?? detectProvider();
251
+ // Create provider context WITHOUT activating globally
252
+ // This is critical for parallel agent support - each agent gets its own context
253
+ // without affecting the global state that other agents might be using
254
+ const providerContext = ProviderContext.create(provider);
255
+ // Get provider-specific settings manager using the context
256
+ const providerSettings = ProviderSettingsManager.forContext(providerContext);
257
+ // Load settings from provider-specific config
229
258
  try {
230
- settingsManager.loadUserSettings();
259
+ providerSettings.loadUserSettings();
231
260
  }
232
261
  catch (error) {
233
- throw new SDKError(SDKErrorCode.SETUP_NOT_RUN, 'ax-cli setup has not been run. Please run "ax-cli setup" to configure your API key, model, and base URL before using the SDK.', error instanceof Error ? error : undefined);
262
+ const cliName = PROVIDER_CONFIGS[provider].cliName;
263
+ throw new SDKError(SDKErrorCode.SETUP_NOT_RUN, `${cliName} setup has not been run. Please run "${cliName} setup" to configure your API key, model, and base URL before using the SDK.`, error instanceof Error ? error : undefined);
234
264
  }
235
- // Get configuration ONLY from settings (security requirement)
236
- const apiKey = settingsManager.getApiKey();
237
- const model = settingsManager.getCurrentModel();
238
- const baseURL = settingsManager.getBaseURL();
265
+ // Get configuration from provider-specific settings
266
+ const apiKey = providerSettings.getApiKey();
267
+ const model = providerSettings.getCurrentModel();
268
+ const baseURL = providerSettings.getBaseURL();
239
269
  // Validate required settings exist
270
+ const cliName = PROVIDER_CONFIGS[provider].cliName;
240
271
  if (!apiKey) {
241
- throw new SDKError(SDKErrorCode.API_KEY_MISSING, 'No API key configured. Please run "ax-cli setup" to configure your credentials.');
272
+ throw new SDKError(SDKErrorCode.API_KEY_MISSING, `No API key configured for ${provider}. Please run "${cliName} setup" to configure your credentials.`);
242
273
  }
243
274
  if (!baseURL) {
244
- throw new SDKError(SDKErrorCode.BASE_URL_MISSING, 'No base URL configured. Please run "ax-cli setup" to configure your API provider.');
275
+ throw new SDKError(SDKErrorCode.BASE_URL_MISSING, `No base URL configured for ${provider}. Please run "${cliName} setup" to configure your API provider.`);
276
+ }
277
+ // BUG FIX: Validate model is configured before creating agent
278
+ // Without this, undefined model would fall back to getSettingsManager().getCurrentModel()
279
+ // which uses the OLD singleton-based settings manager, not the provider-aware one.
280
+ // This could cause the agent to use a different model in multi-provider scenarios.
281
+ if (!model) {
282
+ throw new SDKError(SDKErrorCode.MODEL_MISSING, `No model configured for ${provider}. Please run "${cliName} setup" to configure your AI model.`);
245
283
  }
246
284
  // Apply defaults for optional values
247
285
  const maxToolRounds = validated.maxToolRounds; // undefined is valid, LLMAgent uses 400 as default
@@ -252,6 +290,8 @@ export async function createAgent(options = {}) {
252
290
  // Debug logging
253
291
  if (debug) {
254
292
  console.error('[AX SDK DEBUG] Creating agent with settings:');
293
+ console.error('[AX SDK DEBUG] Provider:', provider);
294
+ console.error('[AX SDK DEBUG] Config dir:', providerContext.userDir);
255
295
  console.error('[AX SDK DEBUG] Model:', model);
256
296
  console.error('[AX SDK DEBUG] Base URL:', baseURL);
257
297
  console.error('[AX SDK DEBUG] Max tool rounds:', maxToolRounds ?? 400);
@@ -262,13 +302,25 @@ export async function createAgent(options = {}) {
262
302
  onError: !!onError
263
303
  });
264
304
  }
265
- // Create agent instance with settings from ax-cli setup
305
+ // Create agent instance with provider-specific settings
266
306
  const agent = new LLMAgent(apiKey, baseURL, model, maxToolRounds);
307
+ // Store provider context on agent for later use
308
+ agent._sdkProvider = provider;
309
+ agent._sdkProviderContext = providerContext;
310
+ agent._sdkProviderSettings = providerSettings;
311
+ // Store the actual model and baseURL used at creation time
312
+ // This prevents getAgentInfo from returning wrong values if config changes
313
+ agent._sdkModel = model;
314
+ agent._sdkBaseURL = baseURL;
315
+ // Store creation timestamp for debugging and lifecycle tracking
316
+ agent._sdkCreatedAt = new Date();
267
317
  // Store lifecycle hooks on agent
268
318
  agent._sdkLifecycleHooks = {
269
319
  onDispose,
270
320
  onError
271
321
  };
322
+ // Store debug flag so disposeAsync can access it for logging
323
+ agent._sdkDebug = debug;
272
324
  // BUG FIX: Track SDK-added listeners so they can be removed on dispose
273
325
  // Without this, listeners would persist after disposal causing memory leaks
274
326
  const sdkListeners = [];
@@ -320,14 +372,23 @@ export async function createAgent(options = {}) {
320
372
  // Without this, calling dispose() multiple times would run cleanup logic and
321
373
  // onDispose hook multiple times, which could cause errors or unexpected behavior
322
374
  let sdkDisposeCompleted = false;
375
+ // Store a reliable disposed flag that works regardless of autoCleanup setting
376
+ agent._sdkDisposed = false;
323
377
  // Phase 3: Wrap dispose() to call onDispose hook
324
378
  const originalDispose = agent.dispose.bind(agent);
379
+ // Store original dispose on agent so disposeAsync can access it
380
+ agent._sdkOriginalDispose = originalDispose;
325
381
  agent.dispose = () => {
326
382
  // BUG FIX: Guard against double disposal in SDK wrapper
327
- if (sdkDisposeCompleted) {
383
+ // Check BOTH the closure variable AND the agent property
384
+ // This handles the case where disposeAsync() was called first (sets _sdkDisposed)
385
+ // or where dispose() was called first (sets sdkDisposeCompleted)
386
+ if (sdkDisposeCompleted || agent._sdkDisposed === true) {
328
387
  return;
329
388
  }
330
389
  sdkDisposeCompleted = true;
390
+ // Set the reliable disposed flag (works regardless of autoCleanup)
391
+ agent._sdkDisposed = true;
331
392
  // Mark as disposed in SDK internal state to prevent auto-cleanup from running again
332
393
  const markDisposed = agent._sdkMarkDisposed;
333
394
  if (markDisposed) {
@@ -422,20 +483,183 @@ export async function createAgent(options = {}) {
422
483
  }
423
484
  return agent;
424
485
  }
486
+ /**
487
+ * Create an agent configured for GLM (Z.AI)
488
+ *
489
+ * Convenience function that creates an agent with provider: 'glm'.
490
+ * Uses configuration from ~/.ax-glm/config.json.
491
+ *
492
+ * @param options - Agent options (provider is set to 'glm')
493
+ * @returns Configured LLM Agent for GLM
494
+ *
495
+ * @example
496
+ * ```typescript
497
+ * const agent = await createGLMAgent();
498
+ * const result = await agent.processUserMessage('Hello');
499
+ * agent.dispose();
500
+ * ```
501
+ */
502
+ export async function createGLMAgent(options = {}) {
503
+ return createAgent({ ...options, provider: 'glm' });
504
+ }
505
+ /**
506
+ * Create an agent configured for Grok (xAI)
507
+ *
508
+ * Convenience function that creates an agent with provider: 'grok'.
509
+ * Uses configuration from ~/.ax-grok/config.json.
510
+ *
511
+ * @param options - Agent options (provider is set to 'grok')
512
+ * @returns Configured LLM Agent for Grok
513
+ *
514
+ * @example
515
+ * ```typescript
516
+ * const agent = await createGrokAgent();
517
+ * const result = await agent.processUserMessage('Hello');
518
+ * agent.dispose();
519
+ * ```
520
+ */
521
+ export async function createGrokAgent(options = {}) {
522
+ return createAgent({ ...options, provider: 'grok' });
523
+ }
524
+ /**
525
+ * Create an agent without throwing errors
526
+ *
527
+ * Unlike createAgent(), this function returns a result object instead of throwing.
528
+ * Useful for graceful error handling without try-catch blocks.
529
+ *
530
+ * @param options - Agent configuration options
531
+ * @returns Result object with either agent or error
532
+ *
533
+ * @example
534
+ * ```typescript
535
+ * const result = await tryCreateAgent({ provider: 'glm' });
536
+ *
537
+ * if (result.success) {
538
+ * // Use agent
539
+ * await result.agent.processUserMessage('Hello');
540
+ * result.agent.dispose();
541
+ * } else {
542
+ * // Handle error without try-catch
543
+ * console.error('Failed:', result.error.code, result.error.message);
544
+ * }
545
+ * ```
546
+ */
547
+ export async function tryCreateAgent(options = {}) {
548
+ try {
549
+ const agent = await createAgent(options);
550
+ return { success: true, agent, error: undefined };
551
+ }
552
+ catch (error) {
553
+ const sdkError = SDKError.isSDKError(error)
554
+ ? error
555
+ : new SDKError(SDKErrorCode.INTERNAL_ERROR, error instanceof Error ? error.message : 'Unknown error creating agent', error instanceof Error ? error : undefined);
556
+ return { success: false, agent: undefined, error: sdkError };
557
+ }
558
+ }
559
+ /**
560
+ * Run a function with a temporary agent that is automatically disposed
561
+ *
562
+ * This helper creates an agent, runs your function, and ensures the agent
563
+ * is properly disposed even if an error occurs. Useful for:
564
+ * - One-off agent operations
565
+ * - Scripts that need cleanup guarantees
566
+ * - Testing scenarios
567
+ *
568
+ * @param fn - Function to run with the agent
569
+ * @param options - Agent configuration options
570
+ * @returns Result of the function
571
+ *
572
+ * @example
573
+ * ```typescript
574
+ * // Simple usage
575
+ * const result = await withAgent(async (agent) => {
576
+ * return await agent.processUserMessage('Analyze this code');
577
+ * });
578
+ *
579
+ * // With options
580
+ * const result = await withAgent(
581
+ * async (agent) => {
582
+ * agent.on('stream', console.log);
583
+ * return await agent.processUserMessage('Hello');
584
+ * },
585
+ * { provider: 'glm', maxToolRounds: 50 }
586
+ * );
587
+ * ```
588
+ */
589
+ export async function withAgent(fn, options = {}) {
590
+ const agent = await createAgent(options);
591
+ try {
592
+ return await fn(agent);
593
+ }
594
+ finally {
595
+ // Use disposeAsync to properly await any async onDispose hooks
596
+ await disposeAsync(agent);
597
+ }
598
+ }
599
+ /**
600
+ * Run a function with a temporary agent, returning result or error
601
+ *
602
+ * Combines withAgent and tryCreateAgent - creates agent, runs function,
603
+ * disposes, and returns result without throwing. Ideal for error-tolerant
604
+ * workflows.
605
+ *
606
+ * @param fn - Function to run with the agent
607
+ * @param options - Agent configuration options
608
+ * @returns Result object with either value or error
609
+ *
610
+ * @example
611
+ * ```typescript
612
+ * const result = await tryWithAgent(async (agent) => {
613
+ * return await agent.processUserMessage('Hello');
614
+ * }, { provider: 'grok' });
615
+ *
616
+ * if (result.success) {
617
+ * console.log('Got response:', result.value);
618
+ * } else {
619
+ * console.error('Failed:', result.error.message);
620
+ * }
621
+ * ```
622
+ */
623
+ export async function tryWithAgent(fn, options = {}) {
624
+ const createResult = await tryCreateAgent(options);
625
+ if (!createResult.success) {
626
+ return { success: false, value: undefined, error: createResult.error };
627
+ }
628
+ try {
629
+ const value = await fn(createResult.agent);
630
+ return { success: true, value, error: undefined };
631
+ }
632
+ catch (error) {
633
+ const sdkError = SDKError.isSDKError(error)
634
+ ? error
635
+ : new SDKError(SDKErrorCode.INTERNAL_ERROR, error instanceof Error ? error.message : 'Unknown error during agent operation', error instanceof Error ? error : undefined);
636
+ return { success: false, value: undefined, error: sdkError };
637
+ }
638
+ finally {
639
+ await disposeAsync(createResult.agent);
640
+ }
641
+ }
425
642
  /**
426
643
  * Create a specialized subagent for specific tasks
427
644
  *
428
645
  * @param role - The role/specialty of the subagent
429
- * @param config - Optional configuration overrides
646
+ * @param options - Optional configuration including provider
430
647
  * @returns Configured Subagent instance
431
648
  *
432
649
  * @example
433
650
  * ```typescript
651
+ * // Basic usage
434
652
  * const testAgent = createSubagent(SubagentRole.TESTING, {
435
653
  * maxToolRounds: 20,
436
654
  * priority: 2
437
655
  * });
438
656
  *
657
+ * // With provider for parallel support
658
+ * const glmSubagent = createSubagent(SubagentRole.ANALYSIS, {
659
+ * provider: 'glm',
660
+ * maxToolRounds: 30
661
+ * });
662
+ *
439
663
  * const result = await testAgent.execute({
440
664
  * id: 'task-1',
441
665
  * description: 'Write unit tests for auth module',
@@ -443,16 +667,33 @@ export async function createAgent(options = {}) {
443
667
  * });
444
668
  * ```
445
669
  */
446
- export function createSubagent(role, config) {
670
+ export function createSubagent(role, options) {
447
671
  // BUG FIX: Clone config to prevent external mutation affecting the subagent
448
672
  // Without this, the caller could modify config.allowedTools array after creation
449
673
  // and unexpectedly change which tools the subagent can use
450
- const clonedConfig = config ? {
451
- ...config,
452
- // Deep clone arrays to prevent mutation
453
- allowedTools: config.allowedTools ? [...config.allowedTools] : undefined,
454
- } : undefined;
455
- return new Subagent(role, clonedConfig);
674
+ let clonedConfig;
675
+ if (options) {
676
+ // BUG FIX: Use destructuring to exclude provider instead of setting undefined
677
+ // Setting `provider: undefined` explicitly could cause issues if Subagent
678
+ // constructor checks for presence of `provider` key vs undefined value
679
+ const { provider: _provider, allowedTools, ...rest } = options;
680
+ clonedConfig = {
681
+ ...rest,
682
+ // Deep clone arrays to prevent mutation
683
+ allowedTools: allowedTools ? [...allowedTools] : undefined,
684
+ };
685
+ }
686
+ // Create subagent
687
+ const subagent = new Subagent(role, clonedConfig);
688
+ // Store provider context if specified for later use
689
+ if (options?.provider) {
690
+ const providerContext = ProviderContext.create(options.provider);
691
+ const providerSettings = ProviderSettingsManager.forContext(providerContext);
692
+ subagent._sdkProvider = options.provider;
693
+ subagent._sdkProviderContext = providerContext;
694
+ subagent._sdkProviderSettings = providerSettings;
695
+ }
696
+ return subagent;
456
697
  }
457
698
  /**
458
699
  * Remove auto-cleanup handlers from an agent
@@ -531,4 +772,501 @@ export async function initializeSDK() {
531
772
  // Initialize MCP servers from settings configured via ax-cli setup
532
773
  await initializeMCPServers();
533
774
  }
775
+ /**
776
+ * Get information about an agent created with createAgent()
777
+ *
778
+ * This function extracts the provider, model, and configuration information
779
+ * from an agent instance. Useful for debugging, logging, and multi-provider
780
+ * scenarios where you need to know which provider an agent is using.
781
+ *
782
+ * @param agent - The agent instance created with createAgent()
783
+ * @returns AgentInfo object with provider/model details, or null if not SDK-created
784
+ *
785
+ * @example
786
+ * ```typescript
787
+ * const glmAgent = await createAgent({ provider: 'glm' });
788
+ * const grokAgent = await createAgent({ provider: 'grok' });
789
+ *
790
+ * const glmInfo = getAgentInfo(glmAgent);
791
+ * console.log(glmInfo?.provider); // 'glm'
792
+ * console.log(glmInfo?.model); // 'glm-4.6'
793
+ *
794
+ * const grokInfo = getAgentInfo(grokAgent);
795
+ * console.log(grokInfo?.provider); // 'grok'
796
+ * console.log(grokInfo?.model); // 'grok-3'
797
+ * ```
798
+ */
799
+ export function getAgentInfo(agent) {
800
+ const provider = agent._sdkProvider;
801
+ const providerContext = agent._sdkProviderContext;
802
+ // BUG FIX: Use stored model/baseURL from creation time, not from settings
803
+ // Settings could change after agent creation, giving wrong info
804
+ const model = agent._sdkModel;
805
+ const baseURL = agent._sdkBaseURL;
806
+ // BUG FIX: Use the reliable _sdkDisposed flag instead of _sdkIsDisposed function
807
+ // _sdkIsDisposed only exists when autoCleanup: true, but _sdkDisposed is always set
808
+ const isDisposed = agent._sdkDisposed;
809
+ const createdAt = agent._sdkCreatedAt;
810
+ if (!provider || !providerContext || !createdAt) {
811
+ // Not created via SDK createAgent()
812
+ return null;
813
+ }
814
+ const config = PROVIDER_CONFIGS[provider];
815
+ return {
816
+ provider,
817
+ providerDisplayName: config.displayName,
818
+ model,
819
+ baseURL,
820
+ isDisposed: isDisposed ?? false,
821
+ configDir: providerContext.userDir,
822
+ cliName: config.cliName,
823
+ createdAt,
824
+ };
825
+ }
826
+ /**
827
+ * Get the model an agent is using
828
+ *
829
+ * Quick accessor to get just the model name from an SDK-created agent.
830
+ * Returns undefined if the agent was not created via createAgent().
831
+ *
832
+ * @param agent - The agent instance
833
+ * @returns The model name or undefined
834
+ *
835
+ * @example
836
+ * ```typescript
837
+ * const agent = await createAgent({ provider: 'glm' });
838
+ * console.log(getAgentModel(agent)); // 'glm-4.6'
839
+ * ```
840
+ */
841
+ export function getAgentModel(agent) {
842
+ return agent._sdkModel;
843
+ }
844
+ /**
845
+ * Get the base URL an agent is using
846
+ *
847
+ * Quick accessor to get just the base URL from an SDK-created agent.
848
+ * Returns undefined if the agent was not created via createAgent().
849
+ *
850
+ * @param agent - The agent instance
851
+ * @returns The base URL or undefined
852
+ *
853
+ * @example
854
+ * ```typescript
855
+ * const agent = await createAgent({ provider: 'grok' });
856
+ * console.log(getAgentBaseURL(agent)); // 'https://api.x.ai/v1'
857
+ * ```
858
+ */
859
+ export function getAgentBaseURL(agent) {
860
+ return agent._sdkBaseURL;
861
+ }
862
+ /**
863
+ * Get the provider an agent is using
864
+ *
865
+ * Quick accessor to get just the provider type from an SDK-created agent.
866
+ * Returns undefined if the agent was not created via createAgent().
867
+ *
868
+ * @param agent - The agent instance
869
+ * @returns The provider type or undefined
870
+ *
871
+ * @example
872
+ * ```typescript
873
+ * const agent = await createAgent({ provider: 'glm' });
874
+ * console.log(getAgentProvider(agent)); // 'glm'
875
+ * ```
876
+ */
877
+ export function getAgentProvider(agent) {
878
+ return agent._sdkProvider;
879
+ }
880
+ /**
881
+ * Get when an agent was created
882
+ *
883
+ * Quick accessor to get the creation timestamp from an SDK-created agent.
884
+ * Useful for logging, monitoring, and debugging agent lifecycle.
885
+ * Returns undefined if the agent was not created via createAgent().
886
+ *
887
+ * @param agent - The agent instance
888
+ * @returns The creation Date or undefined
889
+ *
890
+ * @example
891
+ * ```typescript
892
+ * const agent = await createAgent();
893
+ * console.log(getAgentCreatedAt(agent)); // Date object
894
+ * ```
895
+ */
896
+ export function getAgentCreatedAt(agent) {
897
+ return agent._sdkCreatedAt;
898
+ }
899
+ /**
900
+ * Get how long an agent has been running (age in milliseconds)
901
+ *
902
+ * Returns the time elapsed since the agent was created. Useful for:
903
+ * - Monitoring long-running agents
904
+ * - Implementing agent timeouts
905
+ * - Debugging performance issues
906
+ * - Logging agent lifecycle metrics
907
+ *
908
+ * @param agent - The agent instance
909
+ * @returns Age in milliseconds, or undefined if not SDK-created
910
+ *
911
+ * @example
912
+ * ```typescript
913
+ * const agent = await createAgent();
914
+ *
915
+ * // ... some work ...
916
+ *
917
+ * const ageMs = getAgentAge(agent);
918
+ * if (ageMs !== undefined) {
919
+ * console.log(`Agent running for ${Math.round(ageMs / 1000)}s`);
920
+ *
921
+ * // Implement timeout
922
+ * if (ageMs > 5 * 60 * 1000) { // 5 minutes
923
+ * console.warn('Agent running too long, disposing');
924
+ * agent.dispose();
925
+ * }
926
+ * }
927
+ * ```
928
+ */
929
+ export function getAgentAge(agent) {
930
+ const createdAt = agent._sdkCreatedAt;
931
+ if (!createdAt) {
932
+ return undefined;
933
+ }
934
+ return Date.now() - createdAt.getTime();
935
+ }
936
+ /**
937
+ * Format agent age as human-readable string
938
+ *
939
+ * Convenience function to get agent age as a formatted string.
940
+ * Returns undefined if agent was not created via createAgent().
941
+ *
942
+ * @param agent - The agent instance
943
+ * @returns Formatted age string (e.g., "1m 30s", "2h 15m"), or undefined
944
+ *
945
+ * @example
946
+ * ```typescript
947
+ * const agent = await createAgent();
948
+ * // ... work ...
949
+ * console.log(`Agent age: ${formatAgentAge(agent)}`); // "Agent age: 1m 30s"
950
+ * ```
951
+ */
952
+ export function formatAgentAge(agent) {
953
+ const ageMs = getAgentAge(agent);
954
+ if (ageMs === undefined) {
955
+ return undefined;
956
+ }
957
+ const seconds = Math.floor(ageMs / 1000);
958
+ const minutes = Math.floor(seconds / 60);
959
+ const hours = Math.floor(minutes / 60);
960
+ if (hours > 0) {
961
+ const remainingMinutes = minutes % 60;
962
+ return `${hours}h ${remainingMinutes}m`;
963
+ }
964
+ else if (minutes > 0) {
965
+ const remainingSeconds = seconds % 60;
966
+ return `${minutes}m ${remainingSeconds}s`;
967
+ }
968
+ else {
969
+ return `${seconds}s`;
970
+ }
971
+ }
972
+ /**
973
+ * Check if an agent is busy (bash executing) or disposed
974
+ *
975
+ * This function provides a quick check to determine if an agent is available
976
+ * to process new messages. An agent is considered "busy" if:
977
+ * - It has been disposed (cannot be used at all)
978
+ * - It is currently executing a bash command
979
+ *
980
+ * Useful for:
981
+ * - Pre-flight checks before sending messages
982
+ * - Implementing request queuing
983
+ * - Health monitoring dashboards
984
+ *
985
+ * @param agent - The agent instance to check
986
+ * @returns Object with availability status
987
+ *
988
+ * @example
989
+ * ```typescript
990
+ * const agent = await createAgent();
991
+ *
992
+ * // Check before processing
993
+ * const status = getAgentStatus(agent);
994
+ * if (!status.available) {
995
+ * console.log('Agent not available:', status.reason);
996
+ * return;
997
+ * }
998
+ *
999
+ * await agent.processUserMessage('Hello');
1000
+ * ```
1001
+ */
1002
+ export function getAgentStatus(agent) {
1003
+ const disposed = isAgentDisposed(agent);
1004
+ const isBusy = typeof agent.isBashExecuting === 'function'
1005
+ ? agent.isBashExecuting()
1006
+ : false;
1007
+ const isDisposed = disposed === true;
1008
+ const available = !isDisposed && !isBusy;
1009
+ let reason;
1010
+ if (isDisposed) {
1011
+ reason = 'Agent has been disposed';
1012
+ }
1013
+ else if (isBusy) {
1014
+ reason = 'Agent is currently executing bash command';
1015
+ }
1016
+ return {
1017
+ available,
1018
+ isDisposed,
1019
+ isBusy,
1020
+ reason,
1021
+ ageMs: getAgentAge(agent),
1022
+ };
1023
+ }
1024
+ /**
1025
+ * Check if a provider is properly configured and ready to use
1026
+ *
1027
+ * This function validates that a provider has all required configuration
1028
+ * (API key, base URL, model) without actually creating an agent or making
1029
+ * API calls. Useful for:
1030
+ * - Pre-flight checks before creating agents
1031
+ * - Setup wizards and configuration UIs
1032
+ * - Health checks in long-running services
1033
+ *
1034
+ * @param provider - Provider to check (defaults to auto-detect)
1035
+ * @returns ProviderHealthResult with configuration status
1036
+ *
1037
+ * @example
1038
+ * ```typescript
1039
+ * // Check specific provider
1040
+ * const glmHealth = checkProviderHealth('glm');
1041
+ * if (!glmHealth.healthy) {
1042
+ * console.error('GLM not configured:', glmHealth.message);
1043
+ * console.log('Run: ax-glm setup');
1044
+ * }
1045
+ *
1046
+ * // Check all providers
1047
+ * const providers: ProviderType[] = ['glm', 'grok'];
1048
+ * for (const p of providers) {
1049
+ * const health = checkProviderHealth(p);
1050
+ * console.log(`${p}: ${health.healthy ? '✓' : '✗'} ${health.message}`);
1051
+ * }
1052
+ * ```
1053
+ */
1054
+ export function checkProviderHealth(provider) {
1055
+ const targetProvider = provider ?? detectProvider();
1056
+ const config = PROVIDER_CONFIGS[targetProvider];
1057
+ const settings = ProviderSettingsManager.forProvider(targetProvider);
1058
+ const hasApiKey = !!settings.getApiKey();
1059
+ const hasBaseURL = !!settings.getBaseURL();
1060
+ const hasModel = !!settings.getCurrentModel();
1061
+ const issues = [];
1062
+ if (!hasApiKey)
1063
+ issues.push('API key missing');
1064
+ if (!hasBaseURL)
1065
+ issues.push('Base URL missing');
1066
+ if (!hasModel)
1067
+ issues.push('Model not set');
1068
+ const healthy = hasApiKey && hasBaseURL && hasModel;
1069
+ let message;
1070
+ if (healthy) {
1071
+ message = `${config.displayName} is configured and ready`;
1072
+ }
1073
+ else {
1074
+ message = `${config.displayName} needs configuration: ${issues.join(', ')}`;
1075
+ }
1076
+ return {
1077
+ healthy,
1078
+ provider: targetProvider,
1079
+ hasApiKey,
1080
+ hasBaseURL,
1081
+ hasModel,
1082
+ message,
1083
+ error: healthy ? undefined : `Run "${config.cliName} setup" to configure`,
1084
+ };
1085
+ }
1086
+ /**
1087
+ * Get health status for all supported providers
1088
+ *
1089
+ * @returns Array of health results for all providers
1090
+ *
1091
+ * @example
1092
+ * ```typescript
1093
+ * const allHealth = getAllProviderHealth();
1094
+ * const configured = allHealth.filter(h => h.healthy);
1095
+ * console.log(`${configured.length} providers ready`);
1096
+ * ```
1097
+ */
1098
+ export function getAllProviderHealth() {
1099
+ const providers = ['glm', 'grok', 'generic'];
1100
+ return providers.map(p => checkProviderHealth(p));
1101
+ }
1102
+ // ============================================================================
1103
+ // Agent Lifecycle Utilities (v5.1 - High-Value Features)
1104
+ // ============================================================================
1105
+ /**
1106
+ * Check if an agent has been disposed
1107
+ *
1108
+ * This function provides a reliable way to check if an agent created with
1109
+ * createAgent() has been disposed. Works regardless of the `autoCleanup` setting.
1110
+ *
1111
+ * @param agent - The agent instance to check
1112
+ * @returns true if the agent has been disposed, false otherwise
1113
+ * @returns undefined if the agent was not created via createAgent()
1114
+ *
1115
+ * @example
1116
+ * ```typescript
1117
+ * const agent = await createAgent();
1118
+ * console.log(isAgentDisposed(agent)); // false
1119
+ *
1120
+ * agent.dispose();
1121
+ * console.log(isAgentDisposed(agent)); // true
1122
+ * ```
1123
+ */
1124
+ export function isAgentDisposed(agent) {
1125
+ const disposed = agent._sdkDisposed;
1126
+ if (disposed === undefined) {
1127
+ // Not created via SDK createAgent()
1128
+ return undefined;
1129
+ }
1130
+ return disposed;
1131
+ }
1132
+ /**
1133
+ * Dispose an agent asynchronously, properly awaiting the onDispose hook
1134
+ *
1135
+ * The standard `agent.dispose()` is synchronous and fires async onDispose hooks
1136
+ * in a fire-and-forget manner. Use this function when you need to ensure the
1137
+ * onDispose hook completes before continuing.
1138
+ *
1139
+ * @param agent - The agent instance to dispose
1140
+ * @returns Promise that resolves when disposal is complete
1141
+ *
1142
+ * @example
1143
+ * ```typescript
1144
+ * const agent = await createAgent({
1145
+ * onDispose: async () => {
1146
+ * await saveState(); // This WILL be awaited with disposeAsync
1147
+ * }
1148
+ * });
1149
+ *
1150
+ * // ... use agent ...
1151
+ *
1152
+ * // Properly await cleanup
1153
+ * await disposeAsync(agent);
1154
+ * console.log('Cleanup complete, state saved');
1155
+ * ```
1156
+ */
1157
+ export async function disposeAsync(agent) {
1158
+ // Get debug flag for logging
1159
+ const debug = agent._sdkDebug;
1160
+ // Check if this is an SDK-created agent
1161
+ const originalDispose = agent._sdkOriginalDispose;
1162
+ if (typeof originalDispose !== 'function') {
1163
+ // Not created via SDK createAgent() - fall back to regular dispose
1164
+ // This is a graceful fallback for non-SDK agents
1165
+ if (debug) {
1166
+ console.error('[AX SDK DEBUG] disposeAsync: Agent not created via createAgent(), using regular dispose');
1167
+ }
1168
+ agent.dispose();
1169
+ return;
1170
+ }
1171
+ // Check if already disposed
1172
+ const disposed = agent._sdkDisposed;
1173
+ if (disposed === true) {
1174
+ if (debug) {
1175
+ console.error('[AX SDK DEBUG] disposeAsync: Agent already disposed, skipping');
1176
+ }
1177
+ return; // Already disposed
1178
+ }
1179
+ // Get the onDispose hook if it exists
1180
+ const hooks = agent._sdkLifecycleHooks;
1181
+ const onDispose = hooks?.onDispose;
1182
+ // Mark as disposed to prevent sync dispose() from running cleanup again
1183
+ agent._sdkDisposed = true;
1184
+ // Also mark the autoCleanup tracker as disposed to prevent signal handlers from triggering
1185
+ const markDisposed = agent._sdkMarkDisposed;
1186
+ if (markDisposed) {
1187
+ markDisposed();
1188
+ }
1189
+ // Call onDispose hook and await if it returns a promise
1190
+ if (onDispose) {
1191
+ try {
1192
+ if (debug) {
1193
+ console.error('[AX SDK DEBUG] disposeAsync: Calling onDispose hook');
1194
+ }
1195
+ const result = onDispose();
1196
+ if (result && typeof result.then === 'function') {
1197
+ await result;
1198
+ }
1199
+ if (debug) {
1200
+ console.error('[AX SDK DEBUG] disposeAsync: onDispose hook completed');
1201
+ }
1202
+ }
1203
+ catch (error) {
1204
+ // Log but don't throw - disposal should complete even if hook fails
1205
+ if (debug) {
1206
+ console.error('[AX SDK DEBUG] disposeAsync: Error in onDispose hook:', error);
1207
+ }
1208
+ // Users should handle errors in their onDispose hook
1209
+ }
1210
+ }
1211
+ // Remove cleanup handlers from process event listeners
1212
+ const cleanupHandler = agent._sdkCleanupHandler;
1213
+ if (cleanupHandler) {
1214
+ process.removeListener('exit', cleanupHandler);
1215
+ process.removeListener('SIGINT', cleanupHandler);
1216
+ process.removeListener('SIGTERM', cleanupHandler);
1217
+ process.removeListener('SIGHUP', cleanupHandler);
1218
+ delete agent._sdkCleanupHandler;
1219
+ }
1220
+ // Remove SDK-added event listeners
1221
+ const listeners = agent._sdkListeners;
1222
+ if (listeners && listeners.length > 0 && typeof agent.off === 'function') {
1223
+ for (const { event, listener } of listeners) {
1224
+ agent.off(event, listener);
1225
+ }
1226
+ delete agent._sdkListeners;
1227
+ }
1228
+ // Call the stored original dispose directly, NOT agent.dispose()
1229
+ // agent.dispose() would call our wrapper which would:
1230
+ // 1. Skip because sdkDisposeCompleted might be false (closure variable)
1231
+ // 2. Or run the full wrapper logic including onDispose hook AGAIN
1232
+ // Instead, call _sdkOriginalDispose which is the unwrapped LLMAgent.dispose()
1233
+ originalDispose();
1234
+ if (debug) {
1235
+ console.error('[AX SDK DEBUG] disposeAsync: Disposal complete');
1236
+ }
1237
+ }
1238
+ /**
1239
+ * Get information about a subagent created with createSubagent()
1240
+ *
1241
+ * @param subagent - The subagent instance
1242
+ * @returns SubagentInfo object with provider details
1243
+ *
1244
+ * @example
1245
+ * ```typescript
1246
+ * const subagent = createSubagent(SubagentRole.TESTING, { provider: 'glm' });
1247
+ * const info = getSubagentInfo(subagent);
1248
+ * console.log(info.provider); // 'glm'
1249
+ * console.log(info.role); // SubagentRole.TESTING
1250
+ * ```
1251
+ */
1252
+ export function getSubagentInfo(subagent) {
1253
+ const provider = subagent._sdkProvider;
1254
+ const providerContext = subagent._sdkProviderContext;
1255
+ let providerDisplayName;
1256
+ let configDir;
1257
+ let cliName;
1258
+ if (provider && providerContext) {
1259
+ const config = PROVIDER_CONFIGS[provider];
1260
+ providerDisplayName = config.displayName;
1261
+ configDir = providerContext.userDir;
1262
+ cliName = config.cliName;
1263
+ }
1264
+ return {
1265
+ provider,
1266
+ providerDisplayName,
1267
+ configDir,
1268
+ cliName,
1269
+ role: subagent.role,
1270
+ };
1271
+ }
534
1272
  //# sourceMappingURL=index.js.map