@defai.digital/ax-cli 4.1.10 → 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.
- package/.ax-cli/settings.json +1 -0
- package/README.md +140 -589
- package/dist/agent/dependency-resolver.d.ts +7 -0
- package/dist/agent/dependency-resolver.js +46 -18
- package/dist/agent/dependency-resolver.js.map +1 -1
- package/dist/agent/execution/tool-executor.d.ts +4 -0
- package/dist/agent/execution/tool-executor.js +76 -52
- package/dist/agent/execution/tool-executor.js.map +1 -1
- package/dist/agent/parallel-tools.d.ts +4 -0
- package/dist/agent/parallel-tools.js +65 -24
- package/dist/agent/parallel-tools.js.map +1 -1
- package/dist/agent/planning/plan-executor.d.ts +0 -5
- package/dist/agent/planning/plan-executor.js +23 -6
- package/dist/agent/planning/plan-executor.js.map +1 -1
- package/dist/agent/streaming/stream-handler.js +7 -4
- package/dist/agent/streaming/stream-handler.js.map +1 -1
- package/dist/agent/subagent-orchestrator.d.ts +35 -2
- package/dist/agent/subagent-orchestrator.js +188 -146
- package/dist/agent/subagent-orchestrator.js.map +1 -1
- package/dist/agent/subagent-types.js +3 -1
- package/dist/agent/subagent-types.js.map +1 -1
- package/dist/agent/subagent.d.ts +15 -4
- package/dist/agent/subagent.js +91 -72
- package/dist/agent/subagent.js.map +1 -1
- package/dist/design/figma-alias.d.ts +77 -0
- package/dist/design/figma-alias.js +246 -0
- package/dist/design/figma-alias.js.map +1 -1
- package/dist/design/figma-client.d.ts +4 -0
- package/dist/design/figma-client.js +24 -4
- package/dist/design/figma-client.js.map +1 -1
- package/dist/design/figma-map.js +78 -6
- package/dist/design/figma-map.js.map +1 -1
- package/dist/design/figma-tokens.js +6 -2
- package/dist/design/figma-tokens.js.map +1 -1
- package/dist/design/index.d.ts +1 -1
- package/dist/design/index.js +3 -1
- package/dist/design/index.js.map +1 -1
- package/dist/design/types.d.ts +9 -0
- package/dist/mcp/client-v2.js +4 -0
- package/dist/mcp/client-v2.js.map +1 -1
- package/dist/mcp/config-detector.js +3 -4
- package/dist/mcp/config-detector.js.map +1 -1
- package/dist/mcp/debug.d.ts +207 -0
- package/dist/mcp/debug.js +398 -0
- package/dist/mcp/debug.js.map +1 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/reconnection.js +6 -3
- package/dist/mcp/reconnection.js.map +1 -1
- package/dist/mcp/validation.js +15 -6
- package/dist/mcp/validation.js.map +1 -1
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/index.js +2 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/provider-context-store.d.ts +127 -0
- package/dist/memory/provider-context-store.js +385 -0
- package/dist/memory/provider-context-store.js.map +1 -0
- package/dist/sdk/errors.d.ts +2 -0
- package/dist/sdk/errors.js +2 -0
- package/dist/sdk/errors.js.map +1 -1
- package/dist/sdk/index.d.ts +633 -62
- package/dist/sdk/index.js +854 -116
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/testing.d.ts +46 -4
- package/dist/sdk/testing.js +58 -6
- package/dist/sdk/testing.js.map +1 -1
- package/dist/sdk/version.d.ts +13 -9
- package/dist/sdk/version.js +13 -9
- package/dist/sdk/version.js.map +1 -1
- package/dist/utils/file-lock.d.ts +141 -0
- package/dist/utils/file-lock.js +559 -0
- package/dist/utils/file-lock.js.map +1 -0
- package/dist/utils/provider-context.d.ts +243 -0
- package/dist/utils/provider-context.js +421 -0
- package/dist/utils/provider-context.js.map +1 -0
- package/dist/utils/provider-file-cache.d.ts +91 -0
- package/dist/utils/provider-file-cache.js +165 -0
- package/dist/utils/provider-file-cache.js.map +1 -0
- package/dist/utils/provider-settings.d.ts +181 -0
- package/dist/utils/provider-settings.js +450 -0
- package/dist/utils/provider-settings.js.map +1 -0
- 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
|
-
*
|
|
5
|
-
*
|
|
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
|
-
*
|
|
10
|
-
*
|
|
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 {
|
|
65
|
+
* import { createGLMAgent, SDKError, SDKErrorCode } from '@defai.digital/ax-cli/sdk';
|
|
15
66
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
* ##
|
|
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
|
|
109
|
+
* import { createMockAgent } from '@defai.digital/ax-cli/sdk';
|
|
49
110
|
*
|
|
50
|
-
* const
|
|
51
|
-
* const result = await
|
|
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
|
-
//
|
|
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
|
-
//
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
228
|
-
|
|
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
|
-
|
|
259
|
+
providerSettings.loadUserSettings();
|
|
231
260
|
}
|
|
232
261
|
catch (error) {
|
|
233
|
-
|
|
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
|
|
236
|
-
const apiKey =
|
|
237
|
-
const model =
|
|
238
|
-
const baseURL =
|
|
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,
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
-
|
|
451
|
-
|
|
452
|
-
//
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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
|