@agents-at-scale/ark 0.1.49 → 0.1.50
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 +4 -1
- package/dist/commands/install/index.js +12 -0
- package/dist/commands/models/kubernetes/manifest-builder.js +1 -1
- package/dist/commands/queries/index.js +4 -4
- package/dist/commands/queries/index.spec.d.ts +1 -0
- package/dist/commands/queries/index.spec.js +167 -0
- package/dist/components/ChatUI.js +4 -4
- package/dist/lib/executeQuery.js +4 -6
- package/dist/lib/types.d.ts +2 -2
- package/dist/types/arkService.d.ts +5 -0
- package/package.json +1 -1
package/dist/arkServices.js
CHANGED
|
@@ -119,15 +119,18 @@ const defaultArkServices = {
|
|
|
119
119
|
k8sDeploymentName: 'ark-mcp',
|
|
120
120
|
k8sDevDeploymentName: 'ark-mcp-devspace',
|
|
121
121
|
},
|
|
122
|
+
// ark-broker replaces ark-cluster-memory (renamed in v0.1.49). The old release
|
|
123
|
+
// must be uninstalled first to avoid Helm ownership conflicts on shared
|
|
124
|
+
// resources like the ark-config-streaming ConfigMap.
|
|
122
125
|
'ark-broker': {
|
|
123
126
|
name: 'ark-broker',
|
|
124
127
|
helmReleaseName: 'ark-broker',
|
|
125
128
|
description: 'In-memory storage service with streaming support for Ark queries',
|
|
126
129
|
enabled: true,
|
|
127
130
|
category: 'service',
|
|
128
|
-
// namespace: undefined - uses current context namespace
|
|
129
131
|
chartPath: `${REGISTRY_BASE}/ark-broker`,
|
|
130
132
|
installArgs: [],
|
|
133
|
+
prerequisiteUninstalls: [{ releaseName: 'ark-cluster-memory' }],
|
|
131
134
|
k8sDeploymentName: 'ark-broker',
|
|
132
135
|
k8sDevDeploymentName: 'ark-broker-devspace',
|
|
133
136
|
},
|
|
@@ -10,7 +10,19 @@ import { printNextSteps } from '../../lib/nextSteps.js';
|
|
|
10
10
|
import ora from 'ora';
|
|
11
11
|
import { waitForServicesReady, } from '../../lib/waitForReady.js';
|
|
12
12
|
import { parseTimeoutToSeconds } from '../../lib/timeout.js';
|
|
13
|
+
async function uninstallPrerequisites(service, verbose = false) {
|
|
14
|
+
if (!service.prerequisiteUninstalls?.length)
|
|
15
|
+
return;
|
|
16
|
+
for (const prereq of service.prerequisiteUninstalls) {
|
|
17
|
+
const helmArgs = ['uninstall', prereq.releaseName, '--ignore-not-found'];
|
|
18
|
+
if (prereq.namespace) {
|
|
19
|
+
helmArgs.push('--namespace', prereq.namespace);
|
|
20
|
+
}
|
|
21
|
+
await execute('helm', helmArgs, { stdio: 'inherit' }, { verbose });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
13
24
|
async function installService(service, verbose = false) {
|
|
25
|
+
await uninstallPrerequisites(service, verbose);
|
|
14
26
|
const helmArgs = [
|
|
15
27
|
'upgrade',
|
|
16
28
|
'--install',
|
|
@@ -26,8 +26,8 @@ async function getQuery(name, options) {
|
|
|
26
26
|
try {
|
|
27
27
|
const query = await getResource('queries', name);
|
|
28
28
|
if (options.response) {
|
|
29
|
-
if (query.status?.
|
|
30
|
-
const response = query.status.
|
|
29
|
+
if (query.status?.response) {
|
|
30
|
+
const response = query.status.response;
|
|
31
31
|
if (options.output === 'markdown') {
|
|
32
32
|
console.log(renderMarkdown(response.content || ''));
|
|
33
33
|
}
|
|
@@ -40,8 +40,8 @@ async function getQuery(name, options) {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
else if (options.output === 'markdown') {
|
|
43
|
-
if (query.status?.
|
|
44
|
-
console.log(renderMarkdown(query.status.
|
|
43
|
+
if (query.status?.response) {
|
|
44
|
+
console.log(renderMarkdown(query.status.response.content || ''));
|
|
45
45
|
}
|
|
46
46
|
else {
|
|
47
47
|
output.warning('No response available');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import output from '../../lib/output.js';
|
|
3
|
+
const mockExeca = jest.fn();
|
|
4
|
+
jest.unstable_mockModule('execa', () => ({
|
|
5
|
+
execa: mockExeca,
|
|
6
|
+
}));
|
|
7
|
+
const { createQueriesCommand } = await import('./index.js');
|
|
8
|
+
describe('queries get command', () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
jest.clearAllMocks();
|
|
11
|
+
console.log = jest.fn();
|
|
12
|
+
jest.spyOn(output, 'warning').mockImplementation(() => { });
|
|
13
|
+
jest.spyOn(output, 'error').mockImplementation(() => { });
|
|
14
|
+
jest.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
15
|
+
});
|
|
16
|
+
it('should get query with response in JSON format', async () => {
|
|
17
|
+
const mockQuery = {
|
|
18
|
+
metadata: {
|
|
19
|
+
name: 'test-query',
|
|
20
|
+
},
|
|
21
|
+
spec: {
|
|
22
|
+
input: 'test input',
|
|
23
|
+
target: { type: 'agent', name: 'test-agent' },
|
|
24
|
+
},
|
|
25
|
+
status: {
|
|
26
|
+
phase: 'done',
|
|
27
|
+
response: {
|
|
28
|
+
content: 'This is the response',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
mockExeca.mockResolvedValue({
|
|
33
|
+
stdout: JSON.stringify(mockQuery),
|
|
34
|
+
});
|
|
35
|
+
const command = createQueriesCommand({});
|
|
36
|
+
await command.parseAsync(['node', 'test', 'get', 'test-query']);
|
|
37
|
+
expect(console.log).toHaveBeenCalledWith(JSON.stringify(mockQuery, null, 2));
|
|
38
|
+
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'queries', 'test-query', '-o', 'json'], { stdio: 'pipe' });
|
|
39
|
+
});
|
|
40
|
+
it('should get query with response flag in JSON format', async () => {
|
|
41
|
+
const mockQuery = {
|
|
42
|
+
metadata: {
|
|
43
|
+
name: 'test-query',
|
|
44
|
+
},
|
|
45
|
+
spec: {
|
|
46
|
+
input: 'test input',
|
|
47
|
+
target: { type: 'agent', name: 'test-agent' },
|
|
48
|
+
},
|
|
49
|
+
status: {
|
|
50
|
+
phase: 'done',
|
|
51
|
+
response: {
|
|
52
|
+
content: 'This is the response content',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
mockExeca.mockResolvedValue({
|
|
57
|
+
stdout: JSON.stringify(mockQuery),
|
|
58
|
+
});
|
|
59
|
+
const command = createQueriesCommand({});
|
|
60
|
+
await command.parseAsync([
|
|
61
|
+
'node',
|
|
62
|
+
'test',
|
|
63
|
+
'get',
|
|
64
|
+
'test-query',
|
|
65
|
+
'--response',
|
|
66
|
+
]);
|
|
67
|
+
expect(console.log).toHaveBeenCalledWith(JSON.stringify(mockQuery.status.response, null, 2));
|
|
68
|
+
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'queries', 'test-query', '-o', 'json'], { stdio: 'pipe' });
|
|
69
|
+
});
|
|
70
|
+
it('should get query with response flag in markdown format', async () => {
|
|
71
|
+
const mockQuery = {
|
|
72
|
+
metadata: {
|
|
73
|
+
name: 'test-query',
|
|
74
|
+
},
|
|
75
|
+
spec: {
|
|
76
|
+
input: 'test input',
|
|
77
|
+
target: { type: 'agent', name: 'test-agent' },
|
|
78
|
+
},
|
|
79
|
+
status: {
|
|
80
|
+
phase: 'done',
|
|
81
|
+
response: {
|
|
82
|
+
content: '# Heading\n\nThis is markdown content',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
mockExeca.mockResolvedValue({
|
|
87
|
+
stdout: JSON.stringify(mockQuery),
|
|
88
|
+
});
|
|
89
|
+
const command = createQueriesCommand({});
|
|
90
|
+
await command.parseAsync([
|
|
91
|
+
'node',
|
|
92
|
+
'test',
|
|
93
|
+
'get',
|
|
94
|
+
'test-query',
|
|
95
|
+
'--response',
|
|
96
|
+
'--output',
|
|
97
|
+
'markdown',
|
|
98
|
+
]);
|
|
99
|
+
expect(console.log).toHaveBeenCalled();
|
|
100
|
+
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'queries', 'test-query', '-o', 'json'], { stdio: 'pipe' });
|
|
101
|
+
});
|
|
102
|
+
it('should get query in markdown format without response flag', async () => {
|
|
103
|
+
const mockQuery = {
|
|
104
|
+
metadata: {
|
|
105
|
+
name: 'test-query',
|
|
106
|
+
},
|
|
107
|
+
spec: {
|
|
108
|
+
input: 'test input',
|
|
109
|
+
target: { type: 'agent', name: 'test-agent' },
|
|
110
|
+
},
|
|
111
|
+
status: {
|
|
112
|
+
phase: 'done',
|
|
113
|
+
response: {
|
|
114
|
+
content: '# Response\n\nMarkdown response',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
mockExeca.mockResolvedValue({
|
|
119
|
+
stdout: JSON.stringify(mockQuery),
|
|
120
|
+
});
|
|
121
|
+
const command = createQueriesCommand({});
|
|
122
|
+
await command.parseAsync([
|
|
123
|
+
'node',
|
|
124
|
+
'test',
|
|
125
|
+
'get',
|
|
126
|
+
'test-query',
|
|
127
|
+
'--output',
|
|
128
|
+
'markdown',
|
|
129
|
+
]);
|
|
130
|
+
expect(console.log).toHaveBeenCalled();
|
|
131
|
+
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'queries', 'test-query', '-o', 'json'], { stdio: 'pipe' });
|
|
132
|
+
});
|
|
133
|
+
it('should warn when query has no response with response flag', async () => {
|
|
134
|
+
const mockQuery = {
|
|
135
|
+
metadata: {
|
|
136
|
+
name: 'test-query',
|
|
137
|
+
},
|
|
138
|
+
spec: {
|
|
139
|
+
input: 'test input',
|
|
140
|
+
target: { type: 'agent', name: 'test-agent' },
|
|
141
|
+
},
|
|
142
|
+
status: {
|
|
143
|
+
phase: 'running',
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
mockExeca.mockResolvedValue({
|
|
147
|
+
stdout: JSON.stringify(mockQuery),
|
|
148
|
+
});
|
|
149
|
+
const command = createQueriesCommand({});
|
|
150
|
+
await command.parseAsync([
|
|
151
|
+
'node',
|
|
152
|
+
'test',
|
|
153
|
+
'get',
|
|
154
|
+
'test-query',
|
|
155
|
+
'--response',
|
|
156
|
+
]);
|
|
157
|
+
expect(output.warning).toHaveBeenCalledWith('No response available');
|
|
158
|
+
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'queries', 'test-query', '-o', 'json'], { stdio: 'pipe' });
|
|
159
|
+
});
|
|
160
|
+
it('should handle errors when getting query', async () => {
|
|
161
|
+
mockExeca.mockRejectedValue(new Error('Query not found'));
|
|
162
|
+
const command = createQueriesCommand({});
|
|
163
|
+
await command.parseAsync(['node', 'test', 'get', 'nonexistent-query']);
|
|
164
|
+
expect(output.error).toHaveBeenCalledWith('fetching query:', 'Query not found');
|
|
165
|
+
expect(process.exit).toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
@@ -467,11 +467,11 @@ const ChatUI = ({ initialTargetId, arkApiClient, arkApiProxy, config, }) => {
|
|
|
467
467
|
}
|
|
468
468
|
// Send message and get response with abort signal
|
|
469
469
|
const fullResponse = await chatClientRef.current.sendMessage(target.id, apiMessages, { ...chatConfig, a2aContextId: a2aContextIdRef.current }, (chunk, toolCalls, arkMetadata) => {
|
|
470
|
-
// Extract A2A context ID from
|
|
471
|
-
// Chat TUI always queries a single target, so contextId is in
|
|
472
|
-
if (arkMetadata?.completedQuery?.status?.
|
|
470
|
+
// Extract A2A context ID from response
|
|
471
|
+
// Chat TUI always queries a single target, so contextId is in response
|
|
472
|
+
if (arkMetadata?.completedQuery?.status?.response?.a2a?.contextId) {
|
|
473
473
|
a2aContextIdRef.current =
|
|
474
|
-
arkMetadata.completedQuery.status.
|
|
474
|
+
arkMetadata.completedQuery.status.response.a2a.contextId;
|
|
475
475
|
}
|
|
476
476
|
// Update message progressively as chunks arrive
|
|
477
477
|
setMessages((prev) => {
|
package/dist/lib/executeQuery.js
CHANGED
|
@@ -116,12 +116,10 @@ async function executeQueryWithFormat(options) {
|
|
|
116
116
|
...((options.conversationId || process.env.ARK_CONVERSATION_ID) && {
|
|
117
117
|
conversationId: options.conversationId || process.env.ARK_CONVERSATION_ID,
|
|
118
118
|
}),
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
},
|
|
124
|
-
],
|
|
119
|
+
target: {
|
|
120
|
+
type: options.targetType,
|
|
121
|
+
name: options.targetName,
|
|
122
|
+
},
|
|
125
123
|
},
|
|
126
124
|
};
|
|
127
125
|
try {
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -101,7 +101,7 @@ export interface QueryResponse {
|
|
|
101
101
|
export interface QueryStatus {
|
|
102
102
|
phase?: 'initializing' | 'running' | 'done' | 'error' | 'canceled';
|
|
103
103
|
conditions?: K8sCondition[];
|
|
104
|
-
|
|
104
|
+
response?: QueryResponse;
|
|
105
105
|
message?: string;
|
|
106
106
|
error?: string;
|
|
107
107
|
tokenUsage?: {
|
|
@@ -120,7 +120,7 @@ export interface Query {
|
|
|
120
120
|
metadata: K8sMetadata;
|
|
121
121
|
spec?: {
|
|
122
122
|
input: string;
|
|
123
|
-
|
|
123
|
+
target: QueryTarget;
|
|
124
124
|
sessionId?: string;
|
|
125
125
|
conversationId?: string;
|
|
126
126
|
timeout?: string;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export interface PrerequisiteUninstall {
|
|
2
|
+
releaseName: string;
|
|
3
|
+
namespace?: string;
|
|
4
|
+
}
|
|
1
5
|
export interface ArkService {
|
|
2
6
|
name: string;
|
|
3
7
|
helmReleaseName: string;
|
|
@@ -7,6 +11,7 @@ export interface ArkService {
|
|
|
7
11
|
namespace?: string;
|
|
8
12
|
chartPath?: string;
|
|
9
13
|
installArgs?: string[];
|
|
14
|
+
prerequisiteUninstalls?: PrerequisiteUninstall[];
|
|
10
15
|
k8sServiceName?: string;
|
|
11
16
|
k8sServicePort?: number;
|
|
12
17
|
k8sPortForwardLocalPort?: number;
|