Skip to content

Commit f172302

Browse files
authored
feat: update agent generate endpoint response type [PIC-918] (#2882)
* feat: migrate agent generation endpoint to new response types * fix: prettier issues * feat: update language and jsdoc
1 parent b7f925b commit f172302

10 files changed

Lines changed: 80 additions & 33 deletions

File tree

lib/adapters/REST/endpoints/agent.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { RawAxiosRequestHeaders } from 'axios'
22
import type { AxiosInstance } from 'contentful-sdk-core'
3-
import type { CollectionProp, GetSpaceEnvironmentParams, QueryParams } from '../../../common-types'
3+
import type { CollectionProp, GetSpaceEnvironmentParams } from '../../../common-types'
44
import type { AgentGeneratePayload, AgentProps } from '../../../entities/agent'
5-
import type { AgentRunProps } from '../../../entities/agent-run'
5+
import type { AgentGenerateResponse } from '../../../entities/agent-run'
66
import type { RestEndpoint } from '../types'
77
import * as raw from './raw'
88

@@ -50,7 +50,7 @@ export const generate: RestEndpoint<'Agent', 'generate'> = (
5050
data: AgentGeneratePayload,
5151
headers?: RawAxiosRequestHeaders,
5252
) => {
53-
return raw.post<AgentRunProps>(
53+
return raw.post<AgentGenerateResponse>(
5454
http,
5555
`/spaces/${params.spaceId}/environments/${params.environmentId}/ai_agents/agents/${params.agentId}/generate`,
5656
data,

lib/common-types.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,11 @@ import type {
193193
AiActionInvocationType,
194194
} from './entities/ai-action-invocation'
195195
import type { AgentGeneratePayload, AgentProps } from './entities/agent'
196-
import type { AgentRunProps, AgentRunQueryOptions } from './entities/agent-run'
196+
import type {
197+
AgentGenerateResponse,
198+
AgentRunProps,
199+
AgentRunQueryOptions,
200+
} from './entities/agent-run'
197201
import type {
198202
AutomationDefinitionProps,
199203
AutomationDefinitionQueryOptions,
@@ -1074,7 +1078,7 @@ export type MRActions = {
10741078
params: GetSpaceEnvironmentParams & { agentId: string }
10751079
payload: AgentGeneratePayload
10761080
headers?: RawAxiosRequestHeaders
1077-
return: AgentRunProps
1081+
return: AgentGenerateResponse
10781082
}
10791083
}
10801084
AgentRun: {

lib/create-environment-api.ts

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export default function createEnvironmentApi(makeRequest: MakeRequest) {
101101
const { wrapBulkAction } = entities.bulkAction
102102
const { wrapAppAccessToken } = entities.appAccessToken
103103
const { wrapAgent, wrapAgentCollection } = entities.agent
104-
const { wrapAgentRun, wrapAgentRunCollection } = entities.agentRun
104+
const { wrapAgentRun, wrapAgentRunCollection, wrapAgentGenerateResponse } = entities.agentRun
105105
const { wrapResourceTypesForEnvironmentCollection } = entities.resourceType
106106
const { wrapResourceCollection } = entities.resource
107107
const { wrapSemanticDuplicates } = entities.semanticDuplicates
@@ -2987,31 +2987,38 @@ export default function createEnvironmentApi(makeRequest: MakeRequest) {
29872987
* Generates content using an AI Agent
29882988
* @param agentId - AI Agent ID
29892989
* @param payload - Generation payload
2990-
* @return Promise for the generation response
2990+
* @return Promise for a simplified response containing `sys.id`, `sys.type`, and `sys.status`.
2991+
* Use `getAgentRun()` with the returned `sys.id` to poll for full results.
29912992
* @example ```javascript
29922993
* const contentful = require('contentful-management')
29932994
*
2994-
* const client = contentful.createClient({
2995-
* accessToken: '<content_management_api_key>'
2996-
* })
2995+
* async function generateContent() {
2996+
* const client = contentful.createClient({
2997+
* accessToken: '<content_management_api_key>'
2998+
* })
29972999
*
2998-
* client.getSpace('<space_id>')
2999-
* .then((space) => space.getEnvironment('<environment_id>'))
3000-
* .then((environment) => environment.generateWithAgent('<agent_id>', {
3000+
* const space = await client.getSpace('<space_id>')
3001+
* const environment = await space.getEnvironment('<environment_id>')
3002+
*
3003+
* // Start generation (returns 202 Accepted)
3004+
* const response = await environment.generateWithAgent('<agent_id>', {
30013005
* messages: [
30023006
* {
3003-
* parts: [
3004-
* {
3005-
* type: 'text',
3006-
* text: 'Write a short poem about Contentful'
3007-
* }
3008-
* ],
3007+
* parts: [{ type: 'text', text: 'Write a short poem about Contentful' }],
30093008
* role: 'user'
30103009
* }
30113010
* ]
3012-
* }))
3013-
* .then((result) => console.log(result))
3014-
* .catch(console.error)
3011+
* })
3012+
*
3013+
* // Poll for full results
3014+
* let run = await environment.getAgentRun(response.sys.id)
3015+
* while (run.sys.status === 'IN_PROGRESS') {
3016+
* await new Promise((resolve) => setTimeout(resolve, 1000))
3017+
* run = await environment.getAgentRun(response.sys.id)
3018+
* }
3019+
*
3020+
* console.log(run)
3021+
* }
30153022
* ```
30163023
*/
30173024
generateWithAgent(agentId: string, payload: AgentGeneratePayload) {
@@ -3025,7 +3032,7 @@ export default function createEnvironmentApi(makeRequest: MakeRequest) {
30253032
agentId,
30263033
},
30273034
payload,
3028-
}).then((data) => wrapAgentRun(makeRequest, data))
3035+
}).then((data) => wrapAgentGenerateResponse(makeRequest, data))
30293036
},
30303037

30313038
/**

lib/entities/agent-run.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ import { wrapCollection } from '../common-utils'
55

66
export type AgentRunStatus = 'IN_PROGRESS' | 'FAILED' | 'COMPLETED' | 'PENDING_REVIEW' | 'DRAFT'
77

8+
export type AgentGenerateResponse = {
9+
sys: {
10+
id: string
11+
type: 'AgentRun'
12+
status: AgentRunStatus
13+
}
14+
}
15+
816
export type AgentRunMessageRole = 'system' | 'user' | 'assistant' | 'tool'
917

1018
export type AgentRunMessageTextPart = {
@@ -60,4 +68,12 @@ export function wrapAgentRun(_makeRequest: MakeRequest, data: AgentRunProps): Ag
6068
return freezeSys(agentRun)
6169
}
6270

71+
export function wrapAgentGenerateResponse(
72+
_makeRequest: MakeRequest,
73+
data: AgentGenerateResponse,
74+
): AgentGenerateResponse {
75+
const response = toPlainObject(copy(data))
76+
return freezeSys(response)
77+
}
78+
6379
export const wrapAgentRunCollection = wrapCollection(wrapAgentRun)

lib/entities/agent.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import copy from 'fast-copy'
33
import type { DefaultElements, MakeRequest, MetaSysProps } from '../common-types'
44
import { wrapCollection } from '../common-utils'
55
import enhanceWithMethods from '../enhance-with-methods'
6-
import { wrapAgentRun, type AgentRun } from './agent-run'
6+
import { wrapAgentGenerateResponse, type AgentGenerateResponse } from './agent-run'
77

88
export type AgentToolLink = {
99
sys: {
@@ -44,7 +44,7 @@ export type AgentGeneratePayload<TMetadata = Record<string, unknown>> = {
4444
}
4545

4646
export interface Agent extends AgentProps, DefaultElements<AgentProps> {
47-
generate(payload: AgentGeneratePayload): Promise<AgentRun>
47+
generate(payload: AgentGeneratePayload): Promise<AgentGenerateResponse>
4848
}
4949

5050
function createAgentApi(makeRequest: MakeRequest) {
@@ -62,7 +62,7 @@ function createAgentApi(makeRequest: MakeRequest) {
6262
action: 'generate',
6363
params: getParams(self),
6464
payload,
65-
}).then((data) => wrapAgentRun(makeRequest, data))
65+
}).then((data) => wrapAgentGenerateResponse(makeRequest, data))
6666
},
6767
}
6868
}

lib/export-types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export type { AiAction, AiActionProps, CreateAiActionProps } from './entities/ai
1414
export type { AiActionInvocation, AiActionInvocationProps } from './entities/ai-action-invocation'
1515
export type { Agent, AgentGeneratePayload, AgentProps, AgentToolLink } from './entities/agent'
1616
export type {
17+
AgentGenerateResponse,
1718
AgentRun,
1819
AgentRunMessage,
1920
AgentRunMessagePart,

lib/plain/entities/agent.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { RawAxiosRequestHeaders } from 'axios'
22
import type { CollectionProp, GetSpaceEnvironmentParams, QueryParams } from '../../common-types'
33
import type { AgentGeneratePayload, AgentProps } from '../../entities/agent'
4-
import type { AgentRunProps } from '../../entities/agent-run'
4+
import type { AgentGenerateResponse } from '../../entities/agent-run'
55
import type { OptionalDefaults } from '../wrappers/wrap'
66

77
export type AgentPlainClientAPI = {
@@ -28,12 +28,13 @@ export type AgentPlainClientAPI = {
2828
* @param params Entity IDs to identify the AI Agent.
2929
* @param payload The generation payload.
3030
* @param headers Optional headers for the request.
31-
* @returns A promise resolving with the AI Agent generation response.
31+
* @returns A promise resolving with a simplified response containing `sys.id`, `sys.type`, and `sys.status`.
32+
* Use `agentRun.get()` with the returned `sys.id` to poll for full results.
3233
* @throws if the request fails or the payload is malformed.
3334
*/
3435
generate(
3536
params: OptionalDefaults<GetSpaceEnvironmentParams & { agentId: string }>,
3637
payload: AgentGeneratePayload,
3738
headers?: Partial<RawAxiosRequestHeaders>,
38-
): Promise<AgentRunProps>
39+
): Promise<AgentGenerateResponse>
3940
}

test/integration/agent-integration.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ describe.skipIf(!process.env.API_INTEGRATION_TESTS)('Agent api', { sequential: t
5858
},
5959
],
6060
})
61-
expect(result.result).to.be.ok
61+
expect(result.sys.id, 'sys.id').to.be.ok
62+
expect(result.sys.type, 'sys.type').equals('AgentRun')
63+
expect(result.sys.status, 'sys.status').to.be.ok
6264
})
6365

6466
test('Get specific ai agent run', async () => {

test/unit/mocks/entities.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ import {
9191
AiActionInvocationType,
9292
} from '../../../lib/entities/ai-action-invocation'
9393
import { AgentProps } from '../../../lib/entities/agent'
94-
import { AgentRunProps } from '../../../lib/entities/agent-run'
94+
import { AgentGenerateResponse, AgentRunProps } from '../../../lib/entities/agent-run'
9595
import {
9696
EmbeddingSetStatus,
9797
VectorizationStatusProps,
@@ -1022,6 +1022,14 @@ const agentRunMock: AgentRunProps = {
10221022
],
10231023
}
10241024

1025+
const agentGenerateResponseMock: AgentGenerateResponse = {
1026+
sys: {
1027+
id: 'mocked-agent-run-id',
1028+
type: 'AgentRun' as const,
1029+
status: 'IN_PROGRESS' as const,
1030+
},
1031+
}
1032+
10251033
const apiKeyMock: ApiKeyProps = {
10261034
sys: Object.assign(cloneDeep(sysMock), {
10271035
type: 'ApiKey',
@@ -1563,6 +1571,7 @@ const mocks = {
15631571
aiActionInvocationPayload: aiActionInvocationPayloadMock,
15641572
agent: agentMock,
15651573
agentRun: agentRunMock,
1574+
agentGenerateResponse: agentGenerateResponseMock,
15661575
apiKey: apiKeyMock,
15671576
appAction: appActionMock,
15681577
appActionCall: appActionCallMock,
@@ -1693,6 +1702,7 @@ function setupEntitiesMock() {
16931702
agentRun: {
16941703
wrapAgentRun: vi.fn(),
16951704
wrapAgentRunCollection: vi.fn(),
1705+
wrapAgentGenerateResponse: vi.fn(),
16961706
},
16971707
appAction: {
16981708
wrapAppAction: vi.fn(),

test/unit/plain/agent.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,11 @@ describe('Agent', () => {
7070

7171
test('generate', async () => {
7272
const mockResponse = {
73-
result: 'Generated response',
73+
sys: {
74+
id: 'generated-run-id',
75+
type: 'AgentRun' as const,
76+
status: 'IN_PROGRESS' as const,
77+
},
7478
}
7579
const { httpMock, adapterMock } = setupRestAdapter(Promise.resolve({ data: mockResponse }))
7680
const plainClient = createClient({ apiAdapter: adapterMock }, { type: 'plain' })
@@ -89,7 +93,9 @@ describe('Agent', () => {
8993
const response = await plainClient.agent.generate({ spaceId, environmentId, agentId }, payload)
9094

9195
expect(response).toBeInstanceOf(Object)
92-
expect(response.result).toBe('Generated response')
96+
expect(response.sys.id).toBe('generated-run-id')
97+
expect(response.sys.type).toBe('AgentRun')
98+
expect(response.sys.status).toBe('IN_PROGRESS')
9399

94100
expect(httpMock.post).toHaveBeenCalledWith(
95101
`/spaces/${spaceId}/environments/${environmentId}/ai_agents/agents/${agentId}/generate`,

0 commit comments

Comments
 (0)