Skip to content

Commit ed8120c

Browse files
committed
fix: agent schema and tests
1 parent 3a4937f commit ed8120c

File tree

8 files changed

+356
-53
lines changed

8 files changed

+356
-53
lines changed

src/ai/AkamaiAgentCR.test.ts

Lines changed: 85 additions & 13 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,11 +53,14 @@ 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')
56+
expect(agentCR.spec.agentInstructions).toBe('You are a helpful assistant')
5257
expect(agentCR.spec.tools).toEqual([
5358
{
5459
type: 'knowledgeBase',
5560
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,
5664
},
5765
])
5866
})
@@ -67,19 +75,46 @@ describe('AkamaiAgentCR', () => {
6775
expect(agentCR.metadata.labels?.['custom-label']).toBeUndefined()
6876
})
6977

70-
test('should handle request without knowledgeBase', () => {
71-
const requestWithoutKB = {
78+
test('should handle request without tools', () => {
79+
const requestWithoutTools = {
7280
...mockAgentRequest,
7381
spec: {
7482
...mockAgentRequest.spec,
75-
knowledgeBase: undefined,
83+
tools: undefined,
7684
},
7785
}
7886

79-
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithoutKB)
87+
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithoutTools)
8088

8189
expect(agentCR.spec.tools).toBeUndefined()
8290
})
91+
92+
test('should handle tools with custom description', () => {
93+
const requestWithDescription = {
94+
...mockAgentRequest,
95+
spec: {
96+
...mockAgentRequest.spec,
97+
tools: [
98+
{
99+
type: 'knowledgeBase',
100+
name: 'test-kb',
101+
description: 'Custom description for the knowledge base',
102+
},
103+
],
104+
},
105+
}
106+
107+
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithDescription)
108+
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+
])
117+
})
83118
})
84119

85120
describe('toRecord', () => {
@@ -113,7 +148,15 @@ describe('AkamaiAgentCR', () => {
113148
spec: {
114149
foundationModel: 'gpt-4',
115150
agentInstructions: 'You are a helpful assistant',
116-
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+
],
117160
},
118161
status: {
119162
conditions: [
@@ -128,19 +171,48 @@ describe('AkamaiAgentCR', () => {
128171
})
129172
})
130173

131-
test('should handle empty knowledgeBase in response', () => {
132-
const requestWithoutKB = {
174+
test('should handle empty tools array in response', () => {
175+
const requestWithoutTools = {
133176
...mockAgentRequest,
134177
spec: {
135178
...mockAgentRequest.spec,
136-
knowledgeBase: undefined,
179+
tools: undefined,
137180
},
138181
}
139182

140-
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithoutKB)
183+
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithoutTools)
141184
const response = agentCR.toApiResponse('team-123')
142185

143-
expect(response.spec.knowledgeBase).toBe('')
186+
expect(response.spec.tools).toBeUndefined()
187+
})
188+
189+
test('should preserve custom description and endpoint in response', () => {
190+
const requestWithDetails = {
191+
...mockAgentRequest,
192+
spec: {
193+
...mockAgentRequest.spec,
194+
tools: [
195+
{
196+
type: 'knowledgeBase',
197+
name: 'test-kb',
198+
description: 'Custom KB description',
199+
endpoint: 'https://api.example.com/kb',
200+
},
201+
],
202+
},
203+
}
204+
205+
const agentCR = new AkamaiAgentCR('team-123', 'test-agent', requestWithDetails)
206+
const response = agentCR.toApiResponse('team-123')
207+
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+
])
144216
})
145217
})
146218

@@ -207,7 +279,7 @@ describe('AkamaiAgentCR', () => {
207279
apiVersion: 'akamai.com/v1',
208280
kind: 'Agent',
209281
metadata: { name: 'existing-agent', namespace: 'team-456' },
210-
spec: { foundationModel: 'gpt-3.5', systemPrompt: 'Test prompt' },
282+
spec: { foundationModel: 'gpt-3.5', agentInstructions: 'Test prompt' },
211283
}
212284

213285
const result = AkamaiAgentCR.fromCR(crObject)

src/ai/AkamaiAgentCR.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export class AkamaiAgentCR {
1818
}
1919
public spec: {
2020
foundationModel: string
21-
systemPrompt: string
21+
agentInstructions: string
2222
tools?: Array<{
2323
type: string
2424
name: string
@@ -42,16 +42,17 @@ export class AkamaiAgentCR {
4242
}
4343
this.spec = {
4444
foundationModel: request.spec.foundationModel,
45-
systemPrompt: request.spec.agentInstructions,
46-
tools: request.spec.knowledgeBase
47-
? [
48-
{
49-
type: 'knowledgeBase',
50-
name: request.spec.knowledgeBase,
51-
description: `Search the ${request.spec.knowledgeBase} knowledge base for relevant information. Use this when you need factual information, documentation, or specific details stored in the knowledge base.`,
52-
},
53-
]
54-
: undefined,
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+
})),
5556
}
5657
}
5758

@@ -67,9 +68,6 @@ export class AkamaiAgentCR {
6768

6869
// Transform to API response format
6970
toApiResponse(teamId: string): AplAgentResponse {
70-
// Extract knowledgeBase from tools array (find first knowledgeBase tool)
71-
const knowledgeBaseTool = this.spec.tools?.find((tool) => tool.type === 'knowledgeBase')
72-
7371
return {
7472
kind: 'AkamaiAgent',
7573
metadata: {
@@ -81,8 +79,13 @@ export class AkamaiAgentCR {
8179
},
8280
spec: {
8381
foundationModel: this.spec.foundationModel,
84-
agentInstructions: this.spec.systemPrompt,
85-
knowledgeBase: knowledgeBaseTool?.name || '',
82+
agentInstructions: this.spec.agentInstructions,
83+
tools: this.spec.tools?.map((tool) => ({
84+
type: tool.type,
85+
name: tool.name,
86+
description: tool.description,
87+
endpoint: tool.endpoint,
88+
})),
8689
},
8790
status: {
8891
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/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
@@ -2488,7 +2488,7 @@ export default class OtomiStack {
24882488
spec: {
24892489
foundationModel: data.spec?.foundationModel ?? existingAgent.spec.foundationModel,
24902490
agentInstructions: data.spec?.agentInstructions ?? existingAgent.spec.agentInstructions,
2491-
knowledgeBase: data.spec?.knowledgeBase ?? existingAgent.spec.knowledgeBase,
2491+
tools: (data.spec?.tools ?? existingAgent.spec.tools) as typeof existingAgent.spec.tools,
24922492
},
24932493
})
24942494

0 commit comments

Comments
 (0)