Skip to content

Commit 46d8630

Browse files
committed
Merge remote-tracking branch 'origin/main' into APL-1079
2 parents 3341358 + 1690d2d commit 46d8630

File tree

9 files changed

+370
-46
lines changed

9 files changed

+370
-46
lines changed

src/ai/AkamaiAgentCR.test.ts

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ describe('AkamaiAgentCR', () => {
3030
spec: {
3131
foundationModel: 'gpt-4',
3232
agentInstructions: 'You are a helpful assistant',
33-
knowledgeBase: 'test-kb',
33+
tools: [
34+
{
35+
type: 'knowledgeBase',
36+
name: 'test-kb',
37+
},
38+
],
3439
},
3540
}
3641

@@ -48,8 +53,16 @@ describe('AkamaiAgentCR', () => {
4853
expect(agentCR.metadata.namespace).toBe('team-team-123')
4954
expect(agentCR.metadata.labels?.['apl.io/teamId']).toBe('team-123')
5055
expect(agentCR.spec.foundationModel).toBe('gpt-4')
51-
expect(agentCR.spec.systemPrompt).toBe('You are a helpful assistant')
52-
expect(agentCR.spec.knowledgeBase).toBe('test-kb')
56+
expect(agentCR.spec.agentInstructions).toBe('You are a helpful assistant')
57+
expect(agentCR.spec.tools).toEqual([
58+
{
59+
type: 'knowledgeBase',
60+
name: 'test-kb',
61+
description:
62+
'Search the test-kb knowledge base for relevant information. Use this when you need factual information, documentation, or specific details stored in the knowledge base.',
63+
endpoint: undefined,
64+
},
65+
])
5366
})
5467

5568
test('should set teamId label and not merge custom labels', () => {
@@ -62,18 +75,45 @@ describe('AkamaiAgentCR', () => {
6275
expect(agentCR.metadata.labels?.['custom-label']).toBeUndefined()
6376
})
6477

65-
test('should handle request without knowledgeBase', () => {
66-
const requestWithoutKB = {
78+
test('should handle request without tools', () => {
79+
const requestWithoutTools = {
80+
...mockAgentRequest,
81+
spec: {
82+
...mockAgentRequest.spec,
83+
tools: undefined,
84+
},
85+
}
86+
87+
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithoutTools)
88+
89+
expect(agentCR.spec.tools).toBeUndefined()
90+
})
91+
92+
test('should handle tools with custom description', () => {
93+
const requestWithDescription = {
6794
...mockAgentRequest,
6895
spec: {
6996
...mockAgentRequest.spec,
70-
knowledgeBase: undefined,
97+
tools: [
98+
{
99+
type: 'knowledgeBase',
100+
name: 'test-kb',
101+
description: 'Custom description for the knowledge base',
102+
},
103+
],
71104
},
72105
}
73106

74-
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithoutKB)
107+
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithDescription)
75108

76-
expect(agentCR.spec.knowledgeBase).toBeUndefined()
109+
expect(agentCR.spec.tools).toEqual([
110+
{
111+
type: 'knowledgeBase',
112+
name: 'test-kb',
113+
description: 'Custom description for the knowledge base',
114+
endpoint: undefined,
115+
},
116+
])
77117
})
78118
})
79119

@@ -108,7 +148,15 @@ describe('AkamaiAgentCR', () => {
108148
spec: {
109149
foundationModel: 'gpt-4',
110150
agentInstructions: 'You are a helpful assistant',
111-
knowledgeBase: 'test-kb',
151+
tools: [
152+
{
153+
type: 'knowledgeBase',
154+
name: 'test-kb',
155+
description:
156+
'Search the test-kb knowledge base for relevant information. Use this when you need factual information, documentation, or specific details stored in the knowledge base.',
157+
endpoint: undefined,
158+
},
159+
],
112160
},
113161
status: {
114162
conditions: [
@@ -123,19 +171,48 @@ describe('AkamaiAgentCR', () => {
123171
})
124172
})
125173

126-
test('should handle empty knowledgeBase in response', () => {
127-
const requestWithoutKB = {
174+
test('should handle empty tools array in response', () => {
175+
const requestWithoutTools = {
176+
...mockAgentRequest,
177+
spec: {
178+
...mockAgentRequest.spec,
179+
tools: undefined,
180+
},
181+
}
182+
183+
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithoutTools)
184+
const response = agentCR.toApiResponse('team-123')
185+
186+
expect(response.spec.tools).toBeUndefined()
187+
})
188+
189+
test('should preserve custom description and endpoint in response', () => {
190+
const requestWithDetails = {
128191
...mockAgentRequest,
129192
spec: {
130193
...mockAgentRequest.spec,
131-
knowledgeBase: undefined,
194+
tools: [
195+
{
196+
type: 'knowledgeBase',
197+
name: 'test-kb',
198+
description: 'Custom KB description',
199+
endpoint: 'https://api.example.com/kb',
200+
},
201+
],
132202
},
133203
}
134204

135-
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithoutKB)
205+
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithDetails)
136206
const response = agentCR.toApiResponse('team-123')
137207

138-
expect(response.spec.knowledgeBase).toBe('')
208+
expect(response.spec.tools).toEqual([
209+
{
210+
type: 'knowledgeBase',
211+
name: 'test-kb',
212+
description: 'Custom KB description',
213+
endpoint: 'https://api.example.com/kb',
214+
},
215+
])
139216
})
140217
})
141218

@@ -202,7 +279,7 @@ describe('AkamaiAgentCR', () => {
202279
apiVersion: 'akamai.com/v1',
203280
kind: 'Agent',
204281
metadata: { name: 'existing-agent', namespace: 'team-456' },
205-
spec: { foundationModel: 'gpt-3.5', systemPrompt: 'Test prompt' },
282+
spec: { foundationModel: 'gpt-3.5', agentInstructions: 'Test prompt' },
206283
}
207284

208285
const result = AkamaiAgentCR.fromCR(crObject)

src/ai/AkamaiAgentCR.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@ export class AkamaiAgentCR {
1818
}
1919
public spec: {
2020
foundationModel: string
21-
systemPrompt: string
22-
knowledgeBase?: string
21+
agentInstructions: string
22+
tools?: Array<{
23+
type: string
24+
name: string
25+
description?: string
26+
endpoint?: string
27+
}>
2328
}
2429

2530
constructor(teamId: string, agentName: string, request: AplAgentRequest) {
@@ -37,8 +42,17 @@ export class AkamaiAgentCR {
3742
}
3843
this.spec = {
3944
foundationModel: request.spec.foundationModel,
40-
systemPrompt: request.spec.agentInstructions,
41-
knowledgeBase: request.spec.knowledgeBase,
45+
agentInstructions: request.spec.agentInstructions,
46+
tools: request.spec.tools?.map((tool) => ({
47+
type: tool.type,
48+
name: tool.name,
49+
description:
50+
tool.description ||
51+
(tool.type === 'knowledgeBase'
52+
? `Search the ${tool.name} knowledge base for relevant information. Use this when you need factual information, documentation, or specific details stored in the knowledge base.`
53+
: undefined),
54+
endpoint: tool.endpoint,
55+
})),
4256
}
4357
}
4458

@@ -65,8 +79,13 @@ export class AkamaiAgentCR {
6579
},
6680
spec: {
6781
foundationModel: this.spec.foundationModel,
68-
agentInstructions: this.spec.systemPrompt,
69-
knowledgeBase: this.spec.knowledgeBase || '',
82+
agentInstructions: this.spec.agentInstructions,
83+
tools: this.spec.tools?.map((tool) => ({
84+
type: tool.type,
85+
name: tool.name,
86+
...(tool.description && { description: tool.description }),
87+
...(tool.endpoint && { endpoint: tool.endpoint }),
88+
})),
7089
},
7190
status: {
7291
conditions: [

src/ai/aiModelHandler.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ describe('aiModelHandler', () => {
5252
expect(result).toEqual({
5353
kind: 'AplAIModel',
5454
metadata: {
55-
name: 'gpt-4-deployment',
55+
name: 'gpt-4',
5656
},
5757
spec: {
58-
displayName: 'gpt-4-deployment',
58+
displayName: 'gpt-4',
5959
modelEndpoint: 'http://gpt-4-deployment.ai-models.svc.cluster.local',
6060
modelType: 'foundation',
6161
modelDimension: 1536,
@@ -97,8 +97,8 @@ describe('aiModelHandler', () => {
9797

9898
const result = transformK8sDeploymentToAplAIModel(deploymentWithModelName)
9999

100-
expect(result.metadata.name).toBe('some-deployment-name')
101-
expect(result.spec.displayName).toBe('some-deployment-name')
100+
expect(result.metadata.name).toBe('custom-model-name')
101+
expect(result.spec.displayName).toBe('custom-model-name')
102102
})
103103

104104
test('should use modelName from labels when deployment name is missing', () => {
@@ -231,7 +231,7 @@ describe('aiModelHandler', () => {
231231

232232
const result = transformK8sDeploymentToAplAIModel(deploymentWithoutMetadata)
233233

234-
expect(result.metadata.name).toBeUndefined()
234+
expect(result.metadata.name).toBe('')
235235
expect(result.spec.modelEndpoint).toBe('http://undefined.undefined.svc.cluster.local')
236236
})
237237
})
@@ -244,7 +244,7 @@ describe('aiModelHandler', () => {
244244

245245
expect(result).toHaveLength(1)
246246
expect(result[0].kind).toBe('AplAIModel')
247-
expect(result[0].metadata.name).toBe('gpt-4-deployment')
247+
expect(result[0].metadata.name).toBe('gpt-4')
248248
expect(mockedGetDeploymentsWithAIModelLabels).toHaveBeenCalledTimes(1)
249249
})
250250

@@ -276,8 +276,8 @@ describe('aiModelHandler', () => {
276276
const result = await getAIModels()
277277

278278
expect(result).toHaveLength(2)
279-
expect(result[0].metadata.name).toBe('gpt-4-deployment')
280-
expect(result[1].metadata.name).toBe('embedding-model')
279+
expect(result[0].metadata.name).toBe('gpt-4')
280+
expect(result[1].metadata.name).toBe('text-embedding-ada-002')
281281
})
282282

283283
test('should propagate errors from k8s module', async () => {

src/ai/aiModelHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function getConditions(deployment: V1Deployment) {
1414

1515
export function transformK8sDeploymentToAplAIModel(deployment: V1Deployment): AplAIModelResponse {
1616
const labels = deployment.metadata?.labels || {}
17-
const modelName = deployment.metadata?.name || labels.modelName
17+
const modelName = labels.modelName || deployment.metadata?.name || ''
1818

1919
// Convert K8s deployment conditions to schema format
2020
const conditions = getConditions(deployment)

src/k8s_operations.test.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
import { CoreV1Api } from '@kubernetes/client-node'
22
import { getCloudttyActiveTime, getLogTime } from './k8s_operations'
3+
4+
// Mock the KubeConfig
5+
jest.mock('@kubernetes/client-node', () => {
6+
const actual = jest.requireActual('@kubernetes/client-node')
7+
return {
8+
...actual,
9+
KubeConfig: jest.fn().mockImplementation(() => ({
10+
loadFromDefault: jest.fn(),
11+
makeApiClient: jest.fn((apiClientType) => {
12+
if (apiClientType === actual.CoreV1Api) {
13+
return new actual.CoreV1Api()
14+
}
15+
return {}
16+
}),
17+
})),
18+
}
19+
})
20+
321
describe('getCloudttyLogTime', () => {
422
test('should return the timestamp for a valid log timestamp', () => {
523
const timestampMatch = ['[2023/10/10 00:00:00:0000]', '2023/10/10 00:00:00:0000']
@@ -17,7 +35,7 @@ describe('getCloudttyLogTime', () => {
1735

1836
describe('getCloudttyActiveTime', () => {
1937
afterEach(() => {
20-
jest.restoreAllMocks()
38+
jest.clearAllMocks()
2139
})
2240

2341
test('should return the time difference if no clients', async () => {

src/openapi/agent.yaml

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ Agent:
1919
AplAgentSpec:
2020
type: object
2121
properties:
22-
knowledgeBase:
23-
type: string
24-
description: Name of the knowledge base to use
25-
example: "company-docs"
2622
foundationModel:
2723
type: string
2824
description: Name of the foundation model
@@ -31,6 +27,30 @@ AplAgentSpec:
3127
type: string
3228
description: Custom instructions for the agent
3329
example: "You are a helpful assistant that provides concise answers."
30+
tools:
31+
type: array
32+
description: Tools available to the agent
33+
items:
34+
type: object
35+
properties:
36+
type:
37+
type: string
38+
description: Type of the tool
39+
example: "knowledgeBase"
40+
name:
41+
type: string
42+
description: Name of the tool resource
43+
example: "company-docs"
44+
description:
45+
type: string
46+
description: Description of what the tool does
47+
example: "Search the company-docs knowledge base for relevant information"
48+
endpoint:
49+
type: string
50+
description: Optional endpoint URL for the tool
51+
required:
52+
- type
53+
- name
3454
required:
3555
- foundationModel
3656
- agentInstructions

src/otomi-stack.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2491,7 +2491,7 @@ export default class OtomiStack {
24912491
spec: {
24922492
foundationModel: data.spec?.foundationModel ?? existingAgent.spec.foundationModel,
24932493
agentInstructions: data.spec?.agentInstructions ?? existingAgent.spec.agentInstructions,
2494-
knowledgeBase: data.spec?.knowledgeBase ?? existingAgent.spec.knowledgeBase,
2494+
tools: (data.spec?.tools ?? existingAgent.spec.tools) as typeof existingAgent.spec.tools,
24952495
},
24962496
})
24972497

0 commit comments

Comments
 (0)