@agents-at-scale/ark 0.1.40 → 0.1.42
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/dist/arkServices.js +12 -0
- package/dist/commands/completion/index.js +11 -1
- package/dist/commands/evaluation/index.d.ts +3 -0
- package/dist/commands/evaluation/index.js +60 -0
- package/dist/commands/evaluation/index.spec.d.ts +1 -0
- package/dist/commands/evaluation/index.spec.js +166 -0
- package/dist/commands/memory/index.d.ts +15 -0
- package/dist/commands/memory/index.js +130 -0
- package/dist/commands/memory/index.spec.d.ts +1 -0
- package/dist/commands/memory/index.spec.js +124 -0
- package/dist/commands/models/create.d.ts +5 -6
- package/dist/commands/models/create.js +14 -119
- package/dist/commands/models/create.spec.js +47 -0
- package/dist/commands/models/kubernetes/manifest-builder.d.ts +11 -0
- package/dist/commands/models/kubernetes/manifest-builder.js +109 -0
- package/dist/commands/models/kubernetes/secret-manager.d.ts +7 -0
- package/dist/commands/models/kubernetes/secret-manager.js +20 -0
- package/dist/commands/models/providers/azure.d.ts +31 -0
- package/dist/commands/models/providers/azure.js +82 -0
- package/dist/commands/models/providers/azure.spec.d.ts +1 -0
- package/dist/commands/models/providers/azure.spec.js +230 -0
- package/dist/commands/models/providers/bedrock.d.ts +37 -0
- package/dist/commands/models/providers/bedrock.js +105 -0
- package/dist/commands/models/providers/bedrock.spec.d.ts +1 -0
- package/dist/commands/models/providers/bedrock.spec.js +241 -0
- package/dist/commands/models/providers/factory.d.ts +18 -0
- package/dist/commands/models/providers/factory.js +31 -0
- package/dist/commands/models/providers/index.d.ts +17 -0
- package/dist/commands/models/providers/index.js +9 -0
- package/dist/commands/models/providers/openai.d.ts +28 -0
- package/dist/commands/models/providers/openai.js +68 -0
- package/dist/commands/models/providers/openai.spec.d.ts +1 -0
- package/dist/commands/models/providers/openai.spec.js +180 -0
- package/dist/commands/models/providers/types.d.ts +51 -0
- package/dist/commands/models/providers/types.js +1 -0
- package/dist/commands/queries/index.d.ts +3 -0
- package/dist/commands/queries/index.js +70 -0
- package/dist/commands/query/index.js +3 -1
- package/dist/commands/query/index.spec.js +24 -0
- package/dist/components/ChatUI.js +82 -16
- package/dist/index.js +6 -0
- package/dist/lib/arkApiClient.d.ts +4 -0
- package/dist/lib/arkApiClient.js +55 -0
- package/dist/lib/errors.d.ts +1 -0
- package/dist/lib/errors.js +1 -0
- package/dist/lib/executeEvaluation.d.ts +16 -0
- package/dist/lib/executeEvaluation.js +155 -0
- package/dist/lib/executeQuery.d.ts +1 -0
- package/dist/lib/executeQuery.js +48 -10
- package/dist/lib/executeQuery.spec.js +3 -3
- package/dist/lib/kubectl.d.ts +8 -0
- package/dist/lib/kubectl.js +20 -0
- package/dist/lib/kubectl.spec.d.ts +1 -0
- package/dist/lib/kubectl.spec.js +88 -0
- package/dist/lib/stdin.d.ts +1 -0
- package/dist/lib/stdin.js +16 -0
- package/dist/lib/stdin.spec.d.ts +1 -0
- package/dist/lib/stdin.spec.js +82 -0
- package/dist/lib/types.d.ts +39 -0
- package/dist/ui/TargetSelector.d.ts +19 -0
- package/dist/ui/TargetSelector.js +48 -0
- package/package.json +2 -1
- package/dist/ui/AgentSelector.d.ts +0 -8
- package/dist/ui/AgentSelector.js +0 -53
- package/dist/ui/ModelSelector.d.ts +0 -8
- package/dist/ui/ModelSelector.js +0 -53
- package/dist/ui/TeamSelector.d.ts +0 -8
- package/dist/ui/TeamSelector.js +0 -55
- package/dist/ui/ToolSelector.d.ts +0 -8
- package/dist/ui/ToolSelector.js +0 -53
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider configuration types and collectors.
|
|
3
|
+
*
|
|
4
|
+
* This module exports all provider-specific configurations and their collectors.
|
|
5
|
+
*/
|
|
6
|
+
export { BaseProviderConfig, BaseCollectorOptions, ProviderConfigCollector, } from './types.js';
|
|
7
|
+
export { OpenAIConfig, OpenAICollectorOptions, OpenAIConfigCollector, } from './openai.js';
|
|
8
|
+
export { AzureConfig, AzureCollectorOptions, AzureConfigCollector, } from './azure.js';
|
|
9
|
+
export { BedrockConfig, BedrockCollectorOptions, BedrockConfigCollector, } from './bedrock.js';
|
|
10
|
+
export { ProviderConfigCollectorFactory } from './factory.js';
|
|
11
|
+
import { OpenAIConfig } from './openai.js';
|
|
12
|
+
import { AzureConfig } from './azure.js';
|
|
13
|
+
import { BedrockConfig } from './bedrock.js';
|
|
14
|
+
/**
|
|
15
|
+
* Union type of all supported provider configurations.
|
|
16
|
+
*/
|
|
17
|
+
export type ProviderConfig = OpenAIConfig | AzureConfig | BedrockConfig;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider configuration types and collectors.
|
|
3
|
+
*
|
|
4
|
+
* This module exports all provider-specific configurations and their collectors.
|
|
5
|
+
*/
|
|
6
|
+
export { OpenAIConfigCollector, } from './openai.js';
|
|
7
|
+
export { AzureConfigCollector, } from './azure.js';
|
|
8
|
+
export { BedrockConfigCollector, } from './bedrock.js';
|
|
9
|
+
export { ProviderConfigCollectorFactory } from './factory.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { BaseProviderConfig, BaseCollectorOptions, ProviderConfigCollector } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for OpenAI models.
|
|
4
|
+
*/
|
|
5
|
+
export interface OpenAIConfig extends BaseProviderConfig {
|
|
6
|
+
type: 'openai';
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
apiKey: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Options specific to OpenAI collector.
|
|
12
|
+
*/
|
|
13
|
+
export interface OpenAICollectorOptions extends BaseCollectorOptions {
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
apiKey?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Configuration collector for OpenAI models.
|
|
19
|
+
*
|
|
20
|
+
* Collects the necessary configuration to connect to an OpenAI-compatible API:
|
|
21
|
+
* - baseUrl: The API endpoint URL (e.g., https://api.openai.com/v1)
|
|
22
|
+
* - apiKey: The authentication key for the API
|
|
23
|
+
*
|
|
24
|
+
* Values can be provided via command-line options or will be prompted interactively.
|
|
25
|
+
*/
|
|
26
|
+
export declare class OpenAIConfigCollector implements ProviderConfigCollector {
|
|
27
|
+
collectConfig(options: BaseCollectorOptions): Promise<OpenAIConfig>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration collector for OpenAI models.
|
|
4
|
+
*
|
|
5
|
+
* Collects the necessary configuration to connect to an OpenAI-compatible API:
|
|
6
|
+
* - baseUrl: The API endpoint URL (e.g., https://api.openai.com/v1)
|
|
7
|
+
* - apiKey: The authentication key for the API
|
|
8
|
+
*
|
|
9
|
+
* Values can be provided via command-line options or will be prompted interactively.
|
|
10
|
+
*/
|
|
11
|
+
export class OpenAIConfigCollector {
|
|
12
|
+
async collectConfig(options) {
|
|
13
|
+
const openaiOptions = options;
|
|
14
|
+
let baseUrl = openaiOptions.baseUrl;
|
|
15
|
+
if (!baseUrl) {
|
|
16
|
+
const answer = await inquirer.prompt([
|
|
17
|
+
{
|
|
18
|
+
type: 'input',
|
|
19
|
+
name: 'baseUrl',
|
|
20
|
+
message: 'base URL:',
|
|
21
|
+
validate: (input) => {
|
|
22
|
+
if (!input)
|
|
23
|
+
return 'base URL is required';
|
|
24
|
+
try {
|
|
25
|
+
new URL(input);
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return 'please enter a valid URL';
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
]);
|
|
34
|
+
baseUrl = answer.baseUrl;
|
|
35
|
+
}
|
|
36
|
+
if (!baseUrl) {
|
|
37
|
+
throw new Error('base URL is required');
|
|
38
|
+
}
|
|
39
|
+
baseUrl = baseUrl.replace(/\/$/, '');
|
|
40
|
+
let apiKey = openaiOptions.apiKey;
|
|
41
|
+
if (!apiKey) {
|
|
42
|
+
const answer = await inquirer.prompt([
|
|
43
|
+
{
|
|
44
|
+
type: 'password',
|
|
45
|
+
name: 'apiKey',
|
|
46
|
+
message: 'API key:',
|
|
47
|
+
mask: '*',
|
|
48
|
+
validate: (input) => {
|
|
49
|
+
if (!input)
|
|
50
|
+
return 'API key is required';
|
|
51
|
+
return true;
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
]);
|
|
55
|
+
apiKey = answer.apiKey;
|
|
56
|
+
}
|
|
57
|
+
if (!apiKey) {
|
|
58
|
+
throw new Error('API key is required');
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
type: 'openai',
|
|
62
|
+
modelValue: options.model,
|
|
63
|
+
secretName: '',
|
|
64
|
+
baseUrl,
|
|
65
|
+
apiKey,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
const mockInquirer = {
|
|
3
|
+
prompt: jest.fn(),
|
|
4
|
+
};
|
|
5
|
+
jest.unstable_mockModule('inquirer', () => ({
|
|
6
|
+
default: mockInquirer,
|
|
7
|
+
}));
|
|
8
|
+
const { OpenAIConfigCollector } = await import('./openai.js');
|
|
9
|
+
describe('OpenAIConfigCollector', () => {
|
|
10
|
+
let collector;
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
collector = new OpenAIConfigCollector();
|
|
13
|
+
jest.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
describe('collectConfig', () => {
|
|
16
|
+
it('uses provided options without prompting', async () => {
|
|
17
|
+
const options = {
|
|
18
|
+
model: 'gpt-4o-mini',
|
|
19
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
20
|
+
apiKey: 'sk-test-key-12345',
|
|
21
|
+
};
|
|
22
|
+
const config = await collector.collectConfig(options);
|
|
23
|
+
expect(mockInquirer.prompt).not.toHaveBeenCalled();
|
|
24
|
+
expect(config).toEqual({
|
|
25
|
+
type: 'openai',
|
|
26
|
+
modelValue: 'gpt-4o-mini',
|
|
27
|
+
secretName: '',
|
|
28
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
29
|
+
apiKey: 'sk-test-key-12345',
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
it('prompts for missing baseUrl', async () => {
|
|
33
|
+
mockInquirer.prompt.mockResolvedValueOnce({
|
|
34
|
+
baseUrl: 'https://custom-openai.com',
|
|
35
|
+
});
|
|
36
|
+
mockInquirer.prompt.mockResolvedValueOnce({ apiKey: 'sk-custom-key' });
|
|
37
|
+
const options = {
|
|
38
|
+
model: 'gpt-4',
|
|
39
|
+
};
|
|
40
|
+
const config = await collector.collectConfig(options);
|
|
41
|
+
expect(mockInquirer.prompt).toHaveBeenCalledWith([
|
|
42
|
+
expect.objectContaining({
|
|
43
|
+
type: 'input',
|
|
44
|
+
name: 'baseUrl',
|
|
45
|
+
message: 'base URL:',
|
|
46
|
+
validate: expect.any(Function),
|
|
47
|
+
}),
|
|
48
|
+
]);
|
|
49
|
+
expect(config.baseUrl).toBe('https://custom-openai.com');
|
|
50
|
+
});
|
|
51
|
+
it('validates baseUrl is required', async () => {
|
|
52
|
+
mockInquirer.prompt.mockResolvedValueOnce({ baseUrl: '' });
|
|
53
|
+
const options = {
|
|
54
|
+
model: 'gpt-4',
|
|
55
|
+
};
|
|
56
|
+
// The validation happens in the prompt, but we test the final check
|
|
57
|
+
await expect(collector.collectConfig(options)).rejects.toThrow('base URL is required');
|
|
58
|
+
});
|
|
59
|
+
it('validates baseUrl is a valid URL', async () => {
|
|
60
|
+
const options = {
|
|
61
|
+
model: 'gpt-4',
|
|
62
|
+
};
|
|
63
|
+
// Get the validate function from the prompt call
|
|
64
|
+
mockInquirer.prompt.mockImplementationOnce(async (questions) => {
|
|
65
|
+
const validate = questions[0].validate;
|
|
66
|
+
// Test invalid URL
|
|
67
|
+
expect(validate('not-a-url')).toBe('please enter a valid URL');
|
|
68
|
+
// Test empty string
|
|
69
|
+
expect(validate('')).toBe('base URL is required');
|
|
70
|
+
// Test valid URL
|
|
71
|
+
expect(validate('https://api.openai.com')).toBe(true);
|
|
72
|
+
return { baseUrl: 'https://api.openai.com' };
|
|
73
|
+
});
|
|
74
|
+
mockInquirer.prompt.mockResolvedValueOnce({ apiKey: 'sk-key' });
|
|
75
|
+
await collector.collectConfig(options);
|
|
76
|
+
});
|
|
77
|
+
it('removes trailing slash from baseUrl', async () => {
|
|
78
|
+
const options = {
|
|
79
|
+
model: 'gpt-4',
|
|
80
|
+
baseUrl: 'https://api.openai.com/v1/',
|
|
81
|
+
apiKey: 'sk-test-key',
|
|
82
|
+
};
|
|
83
|
+
const config = await collector.collectConfig(options);
|
|
84
|
+
expect(config.baseUrl).toBe('https://api.openai.com/v1');
|
|
85
|
+
});
|
|
86
|
+
it('prompts for missing apiKey as password field', async () => {
|
|
87
|
+
mockInquirer.prompt.mockResolvedValueOnce({ apiKey: 'sk-secret-key' });
|
|
88
|
+
const options = {
|
|
89
|
+
model: 'gpt-4',
|
|
90
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
91
|
+
};
|
|
92
|
+
const config = await collector.collectConfig(options);
|
|
93
|
+
expect(mockInquirer.prompt).toHaveBeenCalledWith([
|
|
94
|
+
expect.objectContaining({
|
|
95
|
+
type: 'password',
|
|
96
|
+
name: 'apiKey',
|
|
97
|
+
message: 'API key:',
|
|
98
|
+
mask: '*',
|
|
99
|
+
validate: expect.any(Function),
|
|
100
|
+
}),
|
|
101
|
+
]);
|
|
102
|
+
expect(config.apiKey).toBe('sk-secret-key');
|
|
103
|
+
});
|
|
104
|
+
it('validates apiKey is required', async () => {
|
|
105
|
+
mockInquirer.prompt.mockResolvedValueOnce({ apiKey: '' });
|
|
106
|
+
const options = {
|
|
107
|
+
model: 'gpt-4',
|
|
108
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
109
|
+
};
|
|
110
|
+
await expect(collector.collectConfig(options)).rejects.toThrow('API key is required');
|
|
111
|
+
});
|
|
112
|
+
it('tests apiKey validation function', async () => {
|
|
113
|
+
const options = {
|
|
114
|
+
model: 'gpt-4',
|
|
115
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
116
|
+
};
|
|
117
|
+
// Get the validate function from the prompt call
|
|
118
|
+
mockInquirer.prompt.mockImplementationOnce(async (questions) => {
|
|
119
|
+
const validate = questions[0].validate;
|
|
120
|
+
// Test empty string
|
|
121
|
+
expect(validate('')).toBe('API key is required');
|
|
122
|
+
// Test valid key
|
|
123
|
+
expect(validate('sk-valid-key')).toBe(true);
|
|
124
|
+
return { apiKey: 'sk-valid-key' };
|
|
125
|
+
});
|
|
126
|
+
await collector.collectConfig(options);
|
|
127
|
+
});
|
|
128
|
+
it('collects full configuration through interactive prompts', async () => {
|
|
129
|
+
mockInquirer.prompt.mockResolvedValueOnce({
|
|
130
|
+
baseUrl: 'https://api.openai.com/v1/',
|
|
131
|
+
});
|
|
132
|
+
mockInquirer.prompt.mockResolvedValueOnce({
|
|
133
|
+
apiKey: 'sk-proj-abc123',
|
|
134
|
+
});
|
|
135
|
+
const options = {
|
|
136
|
+
model: 'gpt-4o',
|
|
137
|
+
};
|
|
138
|
+
const config = await collector.collectConfig(options);
|
|
139
|
+
expect(config).toEqual({
|
|
140
|
+
type: 'openai',
|
|
141
|
+
modelValue: 'gpt-4o',
|
|
142
|
+
secretName: '',
|
|
143
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
144
|
+
apiKey: 'sk-proj-abc123',
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
it('mixes CLI options and interactive prompts', async () => {
|
|
148
|
+
mockInquirer.prompt.mockResolvedValueOnce({
|
|
149
|
+
apiKey: 'sk-prompted-key',
|
|
150
|
+
});
|
|
151
|
+
const options = {
|
|
152
|
+
model: 'gpt-3.5-turbo',
|
|
153
|
+
baseUrl: 'https://custom-api.com/v1',
|
|
154
|
+
};
|
|
155
|
+
const config = await collector.collectConfig(options);
|
|
156
|
+
expect(config).toEqual({
|
|
157
|
+
type: 'openai',
|
|
158
|
+
modelValue: 'gpt-3.5-turbo',
|
|
159
|
+
secretName: '',
|
|
160
|
+
baseUrl: 'https://custom-api.com/v1',
|
|
161
|
+
apiKey: 'sk-prompted-key',
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
it('handles custom OpenAI-compatible endpoints', async () => {
|
|
165
|
+
const options = {
|
|
166
|
+
model: 'llama-3-8b',
|
|
167
|
+
baseUrl: 'https://localhost:8080/v1',
|
|
168
|
+
apiKey: 'local-key-123',
|
|
169
|
+
};
|
|
170
|
+
const config = await collector.collectConfig(options);
|
|
171
|
+
expect(config).toEqual({
|
|
172
|
+
type: 'openai',
|
|
173
|
+
modelValue: 'llama-3-8b',
|
|
174
|
+
secretName: '',
|
|
175
|
+
baseUrl: 'https://localhost:8080/v1',
|
|
176
|
+
apiKey: 'local-key-123',
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ProviderConfig } from './index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Base configuration shared by all model providers.
|
|
4
|
+
*/
|
|
5
|
+
export interface BaseProviderConfig {
|
|
6
|
+
type: string;
|
|
7
|
+
modelValue: string;
|
|
8
|
+
secretName: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Common options available to all providers collectors.
|
|
12
|
+
*
|
|
13
|
+
* Can be extended with provider-specific options to grant more flexibility when configuring models on different providers.
|
|
14
|
+
*
|
|
15
|
+
* @field model - Model name (e.g., 'gpt-4o-mini')
|
|
16
|
+
* @field type - Model provider type (e.g., 'azure', 'openai', 'bedrock')
|
|
17
|
+
*/
|
|
18
|
+
export interface BaseCollectorOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Model name (e.g., 'gpt-4o-mini')
|
|
21
|
+
*/
|
|
22
|
+
model?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Model provider type (e.g., 'azure', 'openai', 'bedrock')
|
|
25
|
+
*/
|
|
26
|
+
type?: string;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Provider configuration collector interface.
|
|
31
|
+
*
|
|
32
|
+
* A collector is responsible for gathering all the necessary configuration
|
|
33
|
+
* parameters for a specific model provider (OpenAI, Azure, Bedrock, etc.).
|
|
34
|
+
* It handles the interactive prompting of missing values and validation
|
|
35
|
+
* of user inputs, ensuring all required fields are collected before
|
|
36
|
+
* creating the model resource.
|
|
37
|
+
*
|
|
38
|
+
* The collector pattern allows each provider to define its own specific
|
|
39
|
+
* configuration requirements and prompts without affecting other providers.
|
|
40
|
+
*/
|
|
41
|
+
export interface ProviderConfigCollector {
|
|
42
|
+
/**
|
|
43
|
+
* Collects provider-specific configuration by prompting for any missing values.
|
|
44
|
+
*
|
|
45
|
+
* @param options - Options object that may contain pre-filled values.
|
|
46
|
+
* Each collector extracts only the fields it needs.
|
|
47
|
+
* @returns A promise that resolves to a complete provider configuration with all required fields
|
|
48
|
+
* @throws Error if a required field cannot be obtained or validation fails
|
|
49
|
+
*/
|
|
50
|
+
collectConfig(options: BaseCollectorOptions): Promise<ProviderConfig>;
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { marked } from 'marked';
|
|
3
|
+
import TerminalRenderer from 'marked-terminal';
|
|
4
|
+
import output from '../../lib/output.js';
|
|
5
|
+
import { ExitCodes } from '../../lib/errors.js';
|
|
6
|
+
import { getResource } from '../../lib/kubectl.js';
|
|
7
|
+
function renderMarkdown(content) {
|
|
8
|
+
if (process.stdout.isTTY) {
|
|
9
|
+
marked.setOptions({
|
|
10
|
+
// @ts-expect-error - TerminalRenderer types are incomplete
|
|
11
|
+
renderer: new TerminalRenderer({
|
|
12
|
+
showSectionPrefix: false,
|
|
13
|
+
reflowText: true,
|
|
14
|
+
// @ts-expect-error - preserveNewlines exists but not in types
|
|
15
|
+
preserveNewlines: true,
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
return marked(content);
|
|
19
|
+
}
|
|
20
|
+
return content;
|
|
21
|
+
}
|
|
22
|
+
async function getQuery(name, options) {
|
|
23
|
+
try {
|
|
24
|
+
const query = await getResource('queries', name);
|
|
25
|
+
if (options.response) {
|
|
26
|
+
if (query.status?.responses && query.status.responses.length > 0) {
|
|
27
|
+
const response = query.status.responses[0];
|
|
28
|
+
if (options.output === 'markdown') {
|
|
29
|
+
console.log(renderMarkdown(response.content || ''));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.log(JSON.stringify(response, null, 2));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
output.warning('No response available');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (options.output === 'markdown') {
|
|
40
|
+
if (query.status?.responses && query.status.responses.length > 0) {
|
|
41
|
+
console.log(renderMarkdown(query.status.responses[0].content || ''));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
output.warning('No response available');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.log(JSON.stringify(query, null, 2));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
output.error('fetching query:', error instanceof Error ? error.message : error);
|
|
53
|
+
process.exit(ExitCodes.CliError);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function createQueriesCommand(_) {
|
|
57
|
+
const queriesCommand = new Command('queries');
|
|
58
|
+
queriesCommand.description('Manage query resources');
|
|
59
|
+
const getCommand = new Command('get');
|
|
60
|
+
getCommand
|
|
61
|
+
.description('Get a specific query (@latest for most recent)')
|
|
62
|
+
.argument('<name>', 'Query name or @latest')
|
|
63
|
+
.option('-o, --output <format>', 'output format (json, markdown)', 'json')
|
|
64
|
+
.option('-r, --response', 'show only the response content', false)
|
|
65
|
+
.action(async (name, options) => {
|
|
66
|
+
await getQuery(name, options);
|
|
67
|
+
});
|
|
68
|
+
queriesCommand.addCommand(getCommand);
|
|
69
|
+
return queriesCommand;
|
|
70
|
+
}
|
|
@@ -8,7 +8,8 @@ export function createQueryCommand(_) {
|
|
|
8
8
|
.description('Execute a single query against a model or agent')
|
|
9
9
|
.argument('<target>', 'Query target (e.g., model/default, agent/my-agent)')
|
|
10
10
|
.argument('<message>', 'Message to send')
|
|
11
|
-
.
|
|
11
|
+
.option('-o, --output <format>', 'Output format: yaml, json, or name (prints only resource name)')
|
|
12
|
+
.action(async (target, message, options) => {
|
|
12
13
|
const parsed = parseTarget(target);
|
|
13
14
|
if (!parsed) {
|
|
14
15
|
console.error(chalk.red('Invalid target format. Use: model/name or agent/name etc'));
|
|
@@ -18,6 +19,7 @@ export function createQueryCommand(_) {
|
|
|
18
19
|
targetType: parsed.type,
|
|
19
20
|
targetName: parsed.name,
|
|
20
21
|
message,
|
|
22
|
+
outputFormat: options.output,
|
|
21
23
|
});
|
|
22
24
|
});
|
|
23
25
|
return queryCommand;
|
|
@@ -42,6 +42,30 @@ describe('createQueryCommand', () => {
|
|
|
42
42
|
targetType: 'model',
|
|
43
43
|
targetName: 'default',
|
|
44
44
|
message: 'Hello world',
|
|
45
|
+
outputFormat: undefined,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
it('should pass output format option to executeQuery', async () => {
|
|
49
|
+
mockParseTarget.mockReturnValue({
|
|
50
|
+
type: 'model',
|
|
51
|
+
name: 'default',
|
|
52
|
+
});
|
|
53
|
+
mockExecuteQuery.mockResolvedValue(undefined);
|
|
54
|
+
const command = createQueryCommand({});
|
|
55
|
+
await command.parseAsync([
|
|
56
|
+
'node',
|
|
57
|
+
'test',
|
|
58
|
+
'model/default',
|
|
59
|
+
'Hello world',
|
|
60
|
+
'-o',
|
|
61
|
+
'json',
|
|
62
|
+
]);
|
|
63
|
+
expect(mockParseTarget).toHaveBeenCalledWith('model/default');
|
|
64
|
+
expect(mockExecuteQuery).toHaveBeenCalledWith({
|
|
65
|
+
targetType: 'model',
|
|
66
|
+
targetName: 'default',
|
|
67
|
+
message: 'Hello world',
|
|
68
|
+
outputFormat: 'json',
|
|
45
69
|
});
|
|
46
70
|
});
|
|
47
71
|
it('should error on invalid target format', async () => {
|