@agents-at-scale/ark 0.1.35-rc2 → 0.1.36-rc1

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 (37) hide show
  1. package/dist/arkServices.js +7 -7
  2. package/dist/commands/agents/index.js +14 -0
  3. package/dist/commands/completion/index.js +1 -61
  4. package/dist/commands/dev/tool/shared.js +3 -1
  5. package/dist/commands/generate/generators/agent.js +2 -2
  6. package/dist/commands/generate/generators/team.js +2 -2
  7. package/dist/commands/install/index.js +1 -6
  8. package/dist/commands/models/index.js +15 -0
  9. package/dist/commands/models/index.spec.js +20 -0
  10. package/dist/commands/query/index.js +9 -116
  11. package/dist/commands/query/index.spec.d.ts +1 -0
  12. package/dist/commands/query/index.spec.js +53 -0
  13. package/dist/commands/status/index.d.ts +2 -3
  14. package/dist/commands/status/index.js +36 -17
  15. package/dist/commands/targets/index.js +26 -19
  16. package/dist/commands/targets/index.spec.js +95 -46
  17. package/dist/commands/teams/index.js +15 -0
  18. package/dist/commands/uninstall/index.js +0 -5
  19. package/dist/components/statusChecker.d.ts +2 -2
  20. package/dist/index.js +1 -3
  21. package/dist/lib/chatClient.js +70 -76
  22. package/dist/lib/config.d.ts +0 -2
  23. package/dist/lib/executeQuery.d.ts +20 -0
  24. package/dist/lib/executeQuery.js +135 -0
  25. package/dist/lib/executeQuery.spec.d.ts +1 -0
  26. package/dist/lib/executeQuery.spec.js +170 -0
  27. package/dist/lib/nextSteps.js +1 -1
  28. package/dist/lib/queryRunner.d.ts +22 -0
  29. package/dist/lib/queryRunner.js +142 -0
  30. package/dist/lib/startup.d.ts +1 -1
  31. package/dist/lib/startup.js +25 -31
  32. package/dist/lib/startup.spec.js +29 -45
  33. package/dist/lib/types.d.ts +70 -0
  34. package/dist/lib/versions.d.ts +23 -0
  35. package/dist/lib/versions.js +51 -0
  36. package/dist/ui/MainMenu.js +15 -11
  37. package/package.json +1 -2
@@ -1,34 +1,46 @@
1
1
  import { Command } from 'commander';
2
+ import { execa } from 'execa';
2
3
  import output from '../../lib/output.js';
3
- import { ArkApiProxy } from '../../lib/arkApiProxy.js';
4
+ async function fetchResourceTargets(resourceType) {
5
+ const result = await execa('kubectl', ['get', `${resourceType}s`, '-o', 'json'], {
6
+ stdio: 'pipe',
7
+ });
8
+ const data = JSON.parse(result.stdout);
9
+ const items = data.items || [];
10
+ return items.map((item) => ({
11
+ type: resourceType,
12
+ name: item.metadata.name,
13
+ id: `${resourceType}/${item.metadata.name}`,
14
+ available: item.status?.available || item.status?.phase === 'ready' || true,
15
+ }));
16
+ }
4
17
  async function listTargets(options) {
5
- let proxy;
6
18
  try {
7
- proxy = new ArkApiProxy();
8
- const arkApiClient = await proxy.start();
9
- const allTargets = await arkApiClient.getQueryTargets();
10
- // Filter by type if specified
11
- let filteredTargets = allTargets;
12
- if (options.type) {
13
- filteredTargets = allTargets.filter((t) => t.type === options.type);
14
- }
19
+ // Fetch all resource types in parallel
20
+ const resourceTypes = options.type
21
+ ? [options.type]
22
+ : ['model', 'agent', 'team', 'tool'];
23
+ const targetPromises = resourceTypes.map((type) => fetchResourceTargets(type));
24
+ const targetArrays = await Promise.all(targetPromises);
25
+ // Flatten all targets into single array
26
+ const allTargets = targetArrays.flat();
15
27
  // Sort targets by type and name
16
- filteredTargets.sort((a, b) => {
28
+ allTargets.sort((a, b) => {
17
29
  if (a.type !== b.type) {
18
30
  return a.type.localeCompare(b.type);
19
31
  }
20
32
  return a.name.localeCompare(b.name);
21
33
  });
22
34
  if (options.output === 'json') {
23
- console.log(JSON.stringify(filteredTargets, null, 2));
35
+ console.log(JSON.stringify(allTargets, null, 2));
24
36
  }
25
37
  else {
26
- if (filteredTargets.length === 0) {
38
+ if (allTargets.length === 0) {
27
39
  output.warning('no targets available');
28
40
  return;
29
41
  }
30
42
  // Simple list output with type/name format
31
- for (const target of filteredTargets) {
43
+ for (const target of allTargets) {
32
44
  console.log(target.id);
33
45
  }
34
46
  }
@@ -37,11 +49,6 @@ async function listTargets(options) {
37
49
  output.error('fetching targets:', error instanceof Error ? error.message : error);
38
50
  process.exit(1);
39
51
  }
40
- finally {
41
- if (proxy) {
42
- proxy.stop();
43
- }
44
- }
45
52
  }
46
53
  export function createTargetsCommand(_) {
47
54
  const targets = new Command('targets');
@@ -1,17 +1,8 @@
1
1
  import { jest } from '@jest/globals';
2
2
  import { Command } from 'commander';
3
- const mockArkApiClient = {
4
- getQueryTargets: jest.fn(),
5
- };
6
- const mockStart = jest.fn();
7
- mockStart.mockResolvedValue(mockArkApiClient);
8
- const mockArkApiProxy = jest.fn();
9
- mockArkApiProxy.prototype = {
10
- start: mockStart,
11
- stop: jest.fn(),
12
- };
13
- jest.unstable_mockModule('../../lib/arkApiProxy.js', () => ({
14
- ArkApiProxy: mockArkApiProxy,
3
+ // Mock execa to avoid real kubectl calls
4
+ jest.unstable_mockModule('execa', () => ({
5
+ execa: jest.fn(),
15
6
  }));
16
7
  const mockOutput = {
17
8
  warning: jest.fn(),
@@ -24,6 +15,8 @@ const mockExit = jest.spyOn(process, 'exit').mockImplementation((() => {
24
15
  throw new Error('process.exit called');
25
16
  }));
26
17
  const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => { });
18
+ const { execa } = await import('execa');
19
+ const mockExeca = execa;
27
20
  const { createTargetsCommand } = await import('./index.js');
28
21
  describe('targets command', () => {
29
22
  beforeEach(() => {
@@ -35,71 +28,127 @@ describe('targets command', () => {
35
28
  expect(command.name()).toBe('targets');
36
29
  });
37
30
  it('lists targets in text format', async () => {
38
- const mockTargets = [
39
- { id: 'agent/gpt-assistant', type: 'agent', name: 'gpt-assistant' },
40
- { id: 'model/gpt-4', type: 'model', name: 'gpt-4' },
41
- ];
42
- mockArkApiClient.getQueryTargets.mockResolvedValue(mockTargets);
31
+ // Mock kubectl responses for each resource type (order: model, agent, team, tool)
32
+ mockExeca
33
+ .mockResolvedValueOnce({
34
+ stdout: JSON.stringify({
35
+ items: [{ metadata: { name: 'gpt-4' }, status: { available: true } }],
36
+ }),
37
+ })
38
+ .mockResolvedValueOnce({
39
+ stdout: JSON.stringify({
40
+ items: [
41
+ { metadata: { name: 'gpt-assistant' }, status: { phase: 'ready' } },
42
+ ],
43
+ }),
44
+ })
45
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
46
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) });
43
47
  const command = createTargetsCommand({});
44
48
  await command.parseAsync(['node', 'test']);
45
- expect(mockArkApiProxy.prototype.start).toHaveBeenCalled();
46
- expect(mockArkApiClient.getQueryTargets).toHaveBeenCalled();
49
+ expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'models', '-o', 'json'], {
50
+ stdio: 'pipe',
51
+ });
52
+ expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'agents', '-o', 'json'], {
53
+ stdio: 'pipe',
54
+ });
47
55
  expect(mockConsoleLog).toHaveBeenCalledWith('agent/gpt-assistant');
48
56
  expect(mockConsoleLog).toHaveBeenCalledWith('model/gpt-4');
49
- expect(mockArkApiProxy.prototype.stop).toHaveBeenCalled();
50
57
  });
51
58
  it('lists targets in json format', async () => {
52
- const mockTargets = [{ id: 'agent/gpt', type: 'agent', name: 'gpt' }];
53
- mockArkApiClient.getQueryTargets.mockResolvedValue(mockTargets);
59
+ // Order: model, agent, team, tool
60
+ mockExeca
61
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
62
+ .mockResolvedValueOnce({
63
+ stdout: JSON.stringify({
64
+ items: [{ metadata: { name: 'gpt' }, status: { phase: 'ready' } }],
65
+ }),
66
+ })
67
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
68
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) });
54
69
  const command = createTargetsCommand({});
55
70
  await command.parseAsync(['node', 'test', '-o', 'json']);
56
- expect(mockConsoleLog).toHaveBeenCalledWith(JSON.stringify(mockTargets, null, 2));
71
+ const expectedTargets = [
72
+ { type: 'agent', name: 'gpt', id: 'agent/gpt', available: true },
73
+ ];
74
+ expect(mockConsoleLog).toHaveBeenCalledWith(JSON.stringify(expectedTargets, null, 2));
57
75
  });
58
76
  it('filters targets by type', async () => {
59
- const mockTargets = [
60
- { id: 'agent/gpt', type: 'agent', name: 'gpt' },
61
- { id: 'model/claude', type: 'model', name: 'claude' },
62
- { id: 'agent/helper', type: 'agent', name: 'helper' },
63
- ];
64
- mockArkApiClient.getQueryTargets.mockResolvedValue(mockTargets);
77
+ mockExeca.mockResolvedValueOnce({
78
+ stdout: JSON.stringify({
79
+ items: [
80
+ { metadata: { name: 'gpt' }, status: { phase: 'ready' } },
81
+ { metadata: { name: 'helper' }, status: { phase: 'ready' } },
82
+ ],
83
+ }),
84
+ });
65
85
  const command = createTargetsCommand({});
66
86
  await command.parseAsync(['node', 'test', '-t', 'agent']);
87
+ expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'agents', '-o', 'json'], {
88
+ stdio: 'pipe',
89
+ });
90
+ expect(mockExeca).toHaveBeenCalledTimes(1); // Only agents, not other types
67
91
  expect(mockConsoleLog).toHaveBeenCalledWith('agent/gpt');
68
92
  expect(mockConsoleLog).toHaveBeenCalledWith('agent/helper');
69
- expect(mockConsoleLog).not.toHaveBeenCalledWith('model/claude');
70
93
  });
71
94
  it('sorts targets by type then name', async () => {
72
- const mockTargets = [
73
- { id: 'model/b', type: 'model', name: 'b' },
74
- { id: 'agent/z', type: 'agent', name: 'z' },
75
- { id: 'agent/a', type: 'agent', name: 'a' },
76
- { id: 'model/a', type: 'model', name: 'a' },
77
- ];
78
- mockArkApiClient.getQueryTargets.mockResolvedValue(mockTargets);
95
+ // Order: model, agent, team, tool
96
+ mockExeca
97
+ .mockResolvedValueOnce({
98
+ stdout: JSON.stringify({
99
+ items: [
100
+ { metadata: { name: 'b' }, status: { available: true } },
101
+ { metadata: { name: 'a' }, status: { available: true } },
102
+ ],
103
+ }),
104
+ })
105
+ .mockResolvedValueOnce({
106
+ stdout: JSON.stringify({
107
+ items: [
108
+ { metadata: { name: 'z' }, status: { phase: 'ready' } },
109
+ { metadata: { name: 'a' }, status: { phase: 'ready' } },
110
+ ],
111
+ }),
112
+ })
113
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
114
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) });
79
115
  const command = createTargetsCommand({});
80
116
  await command.parseAsync(['node', 'test']);
81
- // Check order of calls
82
- const calls = mockConsoleLog.mock.calls.map((call) => call[0]);
117
+ // Check order of calls - sorted by type then name
118
+ const calls = mockConsoleLog.mock.calls
119
+ .filter((call) => call[0] && call[0].includes('/'))
120
+ .map((call) => call[0]);
83
121
  expect(calls).toEqual(['agent/a', 'agent/z', 'model/a', 'model/b']);
84
122
  });
85
123
  it('shows warning when no targets', async () => {
86
- mockArkApiClient.getQueryTargets.mockResolvedValue([]);
124
+ // All resource types return empty (order: model, agent, team, tool)
125
+ mockExeca
126
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
127
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
128
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
129
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) });
87
130
  const command = createTargetsCommand({});
88
131
  await command.parseAsync(['node', 'test']);
89
132
  expect(mockOutput.warning).toHaveBeenCalledWith('no targets available');
90
133
  });
91
- it('handles errors and stops proxy', async () => {
92
- mockArkApiClient.getQueryTargets.mockRejectedValue(new Error('API failed'));
134
+ it('handles errors', async () => {
135
+ mockExeca.mockRejectedValue(new Error('kubectl not found'));
93
136
  const command = createTargetsCommand({});
94
137
  await expect(command.parseAsync(['node', 'test'])).rejects.toThrow('process.exit called');
95
- expect(mockOutput.error).toHaveBeenCalledWith('fetching targets:', 'API failed');
138
+ expect(mockOutput.error).toHaveBeenCalledWith('fetching targets:', 'kubectl not found');
96
139
  expect(mockExit).toHaveBeenCalledWith(1);
97
- expect(mockArkApiProxy.prototype.stop).toHaveBeenCalled();
98
140
  });
99
141
  it('list subcommand works', async () => {
100
- mockArkApiClient.getQueryTargets.mockResolvedValue([]);
142
+ // Order: model, agent, team, tool
143
+ mockExeca
144
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
145
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
146
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
147
+ .mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) });
101
148
  const command = createTargetsCommand({});
102
149
  await command.parseAsync(['node', 'test', 'list']);
103
- expect(mockArkApiClient.getQueryTargets).toHaveBeenCalled();
150
+ expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'models', '-o', 'json'], {
151
+ stdio: 'pipe',
152
+ });
104
153
  });
105
154
  });
@@ -1,6 +1,7 @@
1
1
  import { Command } from 'commander';
2
2
  import { execa } from 'execa';
3
3
  import output from '../../lib/output.js';
4
+ import { executeQuery } from '../../lib/executeQuery.js';
4
5
  async function listTeams(options) {
5
6
  try {
6
7
  // Use kubectl to get teams
@@ -45,5 +46,19 @@ export function createTeamsCommand(_) {
45
46
  await listTeams(options);
46
47
  });
47
48
  teamsCommand.addCommand(listCommand);
49
+ // Add query command
50
+ const queryCommand = new Command('query');
51
+ queryCommand
52
+ .description('Query a team')
53
+ .argument('<name>', 'Team name')
54
+ .argument('<message>', 'Message to send')
55
+ .action(async (name, message) => {
56
+ await executeQuery({
57
+ targetType: 'team',
58
+ targetName: name,
59
+ message,
60
+ });
61
+ });
62
+ teamsCommand.addCommand(queryCommand);
48
63
  return teamsCommand;
49
64
  }
@@ -22,11 +22,6 @@ async function uninstallArk(config, serviceName, options = {}) {
22
22
  const clusterInfo = config.clusterInfo;
23
23
  // Show cluster info
24
24
  output.success(`connected to cluster: ${chalk.bold(clusterInfo.context)}`);
25
- output.info(`type: ${clusterInfo.type}`);
26
- output.info(`namespace: ${clusterInfo.namespace}`);
27
- if (clusterInfo.ip) {
28
- output.info(`ip: ${clusterInfo.ip}`);
29
- }
30
25
  console.log(); // Add blank line after cluster info
31
26
  // If a specific service is requested, uninstall only that service
32
27
  if (serviceName) {
@@ -1,4 +1,4 @@
1
- import { StatusData, CommandVersionConfig } from '../lib/types.js';
1
+ import { StatusData, CommandVersionConfig, ClusterInfo } from '../lib/types.js';
2
2
  export declare const getNodeVersion: () => CommandVersionConfig;
3
3
  export declare const getNpmVersion: () => CommandVersionConfig;
4
4
  export declare const getKubectlVersion: () => CommandVersionConfig;
@@ -33,6 +33,6 @@ export declare class StatusChecker {
33
33
  */
34
34
  checkAll(): Promise<StatusData & {
35
35
  clusterAccess: boolean;
36
- clusterInfo?: any;
36
+ clusterInfo?: ClusterInfo;
37
37
  }>;
38
38
  }
package/dist/index.js CHANGED
@@ -13,7 +13,6 @@ import { createClusterCommand } from './commands/cluster/index.js';
13
13
  import { createCompletionCommand } from './commands/completion/index.js';
14
14
  import { createDashboardCommand } from './commands/dashboard/index.js';
15
15
  import { createDocsCommand } from './commands/docs/index.js';
16
- import { createDevCommand } from './commands/dev/index.js';
17
16
  import { createGenerateCommand } from './commands/generate/index.js';
18
17
  import { createInstallCommand } from './commands/install/index.js';
19
18
  import { createModelsCommand } from './commands/models/index.js';
@@ -44,13 +43,12 @@ async function main() {
44
43
  program.addCommand(createCompletionCommand(config));
45
44
  program.addCommand(createDashboardCommand(config));
46
45
  program.addCommand(createDocsCommand(config));
47
- program.addCommand(createDevCommand(config));
48
46
  program.addCommand(createGenerateCommand(config));
49
47
  program.addCommand(createInstallCommand(config));
50
48
  program.addCommand(createModelsCommand(config));
51
49
  program.addCommand(createQueryCommand(config));
52
50
  program.addCommand(createUninstallCommand(config));
53
- program.addCommand(createStatusCommand(config));
51
+ program.addCommand(createStatusCommand());
54
52
  program.addCommand(createConfigCommand(config));
55
53
  program.addCommand(createTargetsCommand(config));
56
54
  program.addCommand(createTeamsCommand(config));
@@ -10,90 +10,84 @@ export class ChatClient {
10
10
  */
11
11
  async sendMessage(targetId, messages, config, onChunk, signal) {
12
12
  const shouldStream = config.streamingEnabled && !!onChunk;
13
- try {
14
- const params = {
15
- model: targetId,
16
- messages: messages,
17
- signal: signal,
18
- };
19
- if (shouldStream) {
20
- let fullResponse = '';
21
- const toolCallsById = new Map();
22
- const stream = this.arkApiClient.createChatCompletionStream(params);
23
- for await (const chunk of stream) {
24
- if (signal?.aborted) {
25
- break;
13
+ const params = {
14
+ model: targetId,
15
+ messages: messages,
16
+ signal: signal,
17
+ };
18
+ if (shouldStream) {
19
+ let fullResponse = '';
20
+ const toolCallsById = new Map();
21
+ const stream = this.arkApiClient.createChatCompletionStream(params);
22
+ for await (const chunk of stream) {
23
+ if (signal?.aborted) {
24
+ break;
25
+ }
26
+ const delta = chunk.choices[0]?.delta;
27
+ // Extract ARK metadata if present
28
+ const arkMetadata = chunk.ark;
29
+ // Handle regular content
30
+ const content = delta?.content || '';
31
+ if (content) {
32
+ fullResponse += content;
33
+ if (onChunk) {
34
+ onChunk(content, undefined, arkMetadata);
26
35
  }
27
- const delta = chunk.choices[0]?.delta;
28
- // Extract ARK metadata if present
29
- const arkMetadata = chunk.ark;
30
- // Handle regular content
31
- const content = delta?.content || '';
32
- if (content) {
33
- fullResponse += content;
34
- if (onChunk) {
35
- onChunk(content, undefined, arkMetadata);
36
+ }
37
+ // Handle tool calls
38
+ if (delta?.tool_calls) {
39
+ for (const toolCallDelta of delta.tool_calls) {
40
+ const index = toolCallDelta.index;
41
+ // Initialize tool call if this is the first chunk for this index
42
+ if (!toolCallsById.has(index)) {
43
+ toolCallsById.set(index, {
44
+ id: toolCallDelta.id || '',
45
+ type: toolCallDelta.type || 'function',
46
+ function: {
47
+ name: toolCallDelta.function?.name || '',
48
+ arguments: '',
49
+ },
50
+ });
36
51
  }
37
- }
38
- // Handle tool calls
39
- if (delta?.tool_calls) {
40
- for (const toolCallDelta of delta.tool_calls) {
41
- const index = toolCallDelta.index;
42
- // Initialize tool call if this is the first chunk for this index
43
- if (!toolCallsById.has(index)) {
44
- toolCallsById.set(index, {
45
- id: toolCallDelta.id || '',
46
- type: toolCallDelta.type || 'function',
47
- function: {
48
- name: toolCallDelta.function?.name || '',
49
- arguments: '',
50
- },
51
- });
52
- }
53
- // Accumulate function arguments
54
- const toolCall = toolCallsById.get(index);
55
- if (toolCallDelta.function?.arguments) {
56
- toolCall.function.arguments += toolCallDelta.function.arguments;
57
- }
58
- // Send the current state of all tool calls
59
- if (onChunk) {
60
- const toolCallsArray = Array.from(toolCallsById.values());
61
- onChunk('', toolCallsArray, arkMetadata);
62
- }
52
+ // Accumulate function arguments
53
+ const toolCall = toolCallsById.get(index);
54
+ if (toolCallDelta.function?.arguments) {
55
+ toolCall.function.arguments += toolCallDelta.function.arguments;
56
+ }
57
+ // Send the current state of all tool calls
58
+ if (onChunk) {
59
+ const toolCallsArray = Array.from(toolCallsById.values());
60
+ onChunk('', toolCallsArray, arkMetadata);
63
61
  }
64
62
  }
65
63
  }
66
- return fullResponse;
67
64
  }
68
- else {
69
- const response = await this.arkApiClient.createChatCompletion(params);
70
- const message = response.choices[0]?.message;
71
- const content = message?.content || '';
72
- // Handle tool calls in non-streaming mode
73
- if (message?.tool_calls && message.tool_calls.length > 0) {
74
- const toolCalls = message.tool_calls.map((tc) => ({
75
- id: tc.id,
76
- type: tc.type || 'function',
77
- function: {
78
- name: tc.function?.name || '',
79
- arguments: tc.function?.arguments || '',
80
- },
81
- }));
82
- // Send tool calls first
83
- if (onChunk) {
84
- onChunk('', toolCalls);
85
- }
86
- }
87
- // Send content after tool calls
88
- if (content && onChunk) {
89
- onChunk(content);
65
+ return fullResponse;
66
+ }
67
+ else {
68
+ const response = await this.arkApiClient.createChatCompletion(params);
69
+ const message = response.choices[0]?.message;
70
+ const content = message?.content || '';
71
+ // Handle tool calls in non-streaming mode
72
+ if (message?.tool_calls && message.tool_calls.length > 0) {
73
+ const toolCalls = message.tool_calls.map((tc) => ({
74
+ id: tc.id,
75
+ type: tc.type || 'function',
76
+ function: {
77
+ name: tc.function?.name || '',
78
+ arguments: tc.function?.arguments || '',
79
+ },
80
+ }));
81
+ // Send tool calls first
82
+ if (onChunk) {
83
+ onChunk('', toolCalls);
90
84
  }
91
- return content;
92
85
  }
93
- }
94
- catch (error) {
95
- // Don't log here - error will be displayed in the message thread
96
- throw error;
86
+ // Send content after tool calls
87
+ if (content && onChunk) {
88
+ onChunk(content);
89
+ }
90
+ return content;
97
91
  }
98
92
  }
99
93
  }
@@ -5,8 +5,6 @@ export interface ChatConfig {
5
5
  }
6
6
  export interface ArkConfig {
7
7
  chat?: ChatConfig;
8
- latestVersion?: string;
9
- currentVersion?: string;
10
8
  clusterInfo?: ClusterInfo;
11
9
  }
12
10
  /**
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Shared query execution logic for both universal and resource-specific query commands
3
+ */
4
+ import type { QueryTarget } from './types.js';
5
+ export interface QueryOptions {
6
+ targetType: string;
7
+ targetName: string;
8
+ message: string;
9
+ verbose?: boolean;
10
+ }
11
+ /**
12
+ * Execute a query against any ARK target (model, agent, team)
13
+ * This is the shared implementation used by all query commands
14
+ */
15
+ export declare function executeQuery(options: QueryOptions): Promise<void>;
16
+ /**
17
+ * Parse a target string like "model/default" or "agent/weather"
18
+ * Returns QueryTarget or null if invalid
19
+ */
20
+ export declare function parseTarget(target: string): QueryTarget | null;