Skip to content

Commit 9f29d8c

Browse files
feat: Add hubs support to /ai/ask (box/box-codegen#656) (#507)
1 parent 026c937 commit 9f29d8c

File tree

7 files changed

+221
-141
lines changed

7 files changed

+221
-141
lines changed

.codegen.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{ "engineHash": "7874ac3", "specHash": "1fdcbef", "version": "1.11.0" }
1+
{ "engineHash": "a88aabb", "specHash": "59747aa", "version": "1.11.0" }

docs/ai.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ await client.ai.createAiAsk({
2222
mode: 'multiple_item_qa' as AiAskModeField,
2323
prompt: 'Which direction sun rises?',
2424
items: [
25-
new AiItemBase({
25+
{
2626
id: fileToAsk1.id,
27-
type: 'file' as AiItemBaseTypeField,
27+
type: 'file' as AiItemAskTypeField,
2828
content: 'Earth goes around the sun',
29-
}),
30-
new AiItemBase({
29+
} satisfies AiItemAsk,
30+
{
3131
id: fileToAsk2.id,
32-
type: 'file' as AiItemBaseTypeField,
32+
type: 'file' as AiItemAskTypeField,
3333
content: 'Sun rises in the East in the morning',
34-
}),
34+
} satisfies AiItemAsk,
3535
],
3636
} satisfies AiAsk);
3737
```
@@ -45,9 +45,9 @@ await client.ai.createAiAsk({
4545

4646
### Returns
4747

48-
This function returns a value of type `AiResponseFull`.
48+
This function returns a value of type `undefined | AiResponseFull`.
4949

50-
A successful response including the answer from the LLM.
50+
A successful response including the answer from the LLM.No content is available to answer the question. This is returned when the request item is a hub, but content in the hubs is not indexed. To ensure content in the hub is indexed, make sure Box AI for Hubs in the Admin Console was enabled before hub creation.
5151

5252
## Generate text
5353

package-lock.json

Lines changed: 100 additions & 100 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/managers/ai.generated.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,12 +317,12 @@ export class AiManager {
317317
* Sends an AI request to supported LLMs and returns an answer specifically focused on the user's question given the provided context.
318318
* @param {AiAsk} requestBody Request body of createAiAsk method
319319
* @param {CreateAiAskOptionalsInput} optionalsInput
320-
* @returns {Promise<AiResponseFull>}
320+
* @returns {Promise<undefined | AiResponseFull>}
321321
*/
322322
async createAiAsk(
323323
requestBody: AiAsk,
324324
optionalsInput: CreateAiAskOptionalsInput = {},
325-
): Promise<AiResponseFull> {
325+
): Promise<undefined | AiResponseFull> {
326326
const optionals: CreateAiAskOptionals = new CreateAiAskOptionals({
327327
headers: optionalsInput.headers,
328328
cancellationToken: optionalsInput.cancellationToken,
@@ -349,6 +349,9 @@ export class AiManager {
349349
cancellationToken: cancellationToken,
350350
}),
351351
);
352+
if ((toString(response.status) as string) == '204') {
353+
return void 0;
354+
}
352355
return {
353356
...deserializeAiResponseFull(response.data!),
354357
rawData: response.data!,

src/schemas/aiAsk.generated.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { serializeAiItemBase } from './aiItemBase.generated.js';
2-
import { deserializeAiItemBase } from './aiItemBase.generated.js';
1+
import { serializeAiItemAsk } from './aiItemAsk.generated.js';
2+
import { deserializeAiItemAsk } from './aiItemAsk.generated.js';
33
import { serializeAiDialogueHistory } from './aiDialogueHistory.generated.js';
44
import { deserializeAiDialogueHistory } from './aiDialogueHistory.generated.js';
55
import { serializeAiAgentAsk } from './aiAgentAsk.generated.js';
66
import { deserializeAiAgentAsk } from './aiAgentAsk.generated.js';
7-
import { AiItemBase } from './aiItemBase.generated.js';
7+
import { AiItemAsk } from './aiItemAsk.generated.js';
88
import { AiDialogueHistory } from './aiDialogueHistory.generated.js';
99
import { AiAgentAsk } from './aiAgentAsk.generated.js';
1010
import { BoxSdkError } from '../box/errors.js';
@@ -29,7 +29,7 @@ export interface AiAsk {
2929
* **Note**: Box AI handles documents with text representations up to 1MB in size, or a maximum of 25 files, whichever comes first.
3030
* If the file size exceeds 1MB, the first 1MB of text representation will be processed.
3131
* If you set `mode` parameter to `single_item_qa`, the `items` array can have one element only. */
32-
readonly items: readonly AiItemBase[];
32+
readonly items: readonly AiItemAsk[];
3333
/**
3434
* The history of prompts and answers previously passed to the LLM. This provides additional context to the LLM in generating the response. */
3535
readonly dialogueHistory?: readonly AiDialogueHistory[];
@@ -58,8 +58,8 @@ export function serializeAiAsk(val: AiAsk): SerializedData {
5858
return {
5959
['mode']: serializeAiAskModeField(val.mode),
6060
['prompt']: val.prompt,
61-
['items']: val.items.map(function (item: AiItemBase): SerializedData {
62-
return serializeAiItemBase(item);
61+
['items']: val.items.map(function (item: AiItemAsk): SerializedData {
62+
return serializeAiItemAsk(item);
6363
}) as readonly any[],
6464
['dialogue_history']:
6565
val.dialogueHistory == void 0
@@ -105,9 +105,9 @@ export function deserializeAiAsk(val: SerializedData): AiAsk {
105105
message: 'Expecting array for "items" of type "AiAsk"',
106106
});
107107
}
108-
const items: readonly AiItemBase[] = sdIsList(val.items)
109-
? (val.items.map(function (itm: SerializedData): AiItemBase {
110-
return deserializeAiItemBase(itm);
108+
const items: readonly AiItemAsk[] = sdIsList(val.items)
109+
? (val.items.map(function (itm: SerializedData): AiItemAsk {
110+
return deserializeAiItemAsk(itm);
111111
}) as readonly any[])
112112
: [];
113113
if (!(val.dialogue_history == void 0) && !sdIsList(val.dialogue_history)) {

src/schemas/aiItemAsk.generated.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { BoxSdkError } from '../box/errors.js';
2+
import { SerializedData } from '../serialization/json.js';
3+
import { sdIsEmpty } from '../serialization/json.js';
4+
import { sdIsBoolean } from '../serialization/json.js';
5+
import { sdIsNumber } from '../serialization/json.js';
6+
import { sdIsString } from '../serialization/json.js';
7+
import { sdIsList } from '../serialization/json.js';
8+
import { sdIsMap } from '../serialization/json.js';
9+
export type AiItemAskTypeField = 'file' | 'hubs';
10+
export interface AiItemAsk {
11+
/**
12+
* The ID of the file. */
13+
readonly id: string;
14+
/**
15+
* The type of the item. A `hubs` item must be used as a single item. */
16+
readonly type: AiItemAskTypeField;
17+
/**
18+
* The content of the item, often the text representation. */
19+
readonly content?: string;
20+
readonly rawData?: SerializedData;
21+
}
22+
export function serializeAiItemAskTypeField(
23+
val: AiItemAskTypeField,
24+
): SerializedData {
25+
return val;
26+
}
27+
export function deserializeAiItemAskTypeField(
28+
val: SerializedData,
29+
): AiItemAskTypeField {
30+
if (val == 'file') {
31+
return val;
32+
}
33+
if (val == 'hubs') {
34+
return val;
35+
}
36+
throw new BoxSdkError({ message: "Can't deserialize AiItemAskTypeField" });
37+
}
38+
export function serializeAiItemAsk(val: AiItemAsk): SerializedData {
39+
return {
40+
['id']: val.id,
41+
['type']: serializeAiItemAskTypeField(val.type),
42+
['content']: val.content,
43+
};
44+
}
45+
export function deserializeAiItemAsk(val: SerializedData): AiItemAsk {
46+
if (!sdIsMap(val)) {
47+
throw new BoxSdkError({ message: 'Expecting a map for "AiItemAsk"' });
48+
}
49+
if (val.id == void 0) {
50+
throw new BoxSdkError({
51+
message: 'Expecting "id" of type "AiItemAsk" to be defined',
52+
});
53+
}
54+
if (!sdIsString(val.id)) {
55+
throw new BoxSdkError({
56+
message: 'Expecting string for "id" of type "AiItemAsk"',
57+
});
58+
}
59+
const id: string = val.id;
60+
if (val.type == void 0) {
61+
throw new BoxSdkError({
62+
message: 'Expecting "type" of type "AiItemAsk" to be defined',
63+
});
64+
}
65+
const type: AiItemAskTypeField = deserializeAiItemAskTypeField(val.type);
66+
if (!(val.content == void 0) && !sdIsString(val.content)) {
67+
throw new BoxSdkError({
68+
message: 'Expecting string for "content" of type "AiItemAsk"',
69+
});
70+
}
71+
const content: undefined | string =
72+
val.content == void 0 ? void 0 : val.content;
73+
return { id: id, type: type, content: content } satisfies AiItemAsk;
74+
}

src/test/ai.generated.test.ts

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import { serializeAiAsk } from '../schemas/aiAsk.generated.js';
66
import { deserializeAiAsk } from '../schemas/aiAsk.generated.js';
77
import { serializeAiAskModeField } from '../schemas/aiAsk.generated.js';
88
import { deserializeAiAskModeField } from '../schemas/aiAsk.generated.js';
9-
import { serializeAiItemBase } from '../schemas/aiItemBase.generated.js';
10-
import { deserializeAiItemBase } from '../schemas/aiItemBase.generated.js';
11-
import { serializeAiItemBaseTypeField } from '../schemas/aiItemBase.generated.js';
12-
import { deserializeAiItemBaseTypeField } from '../schemas/aiItemBase.generated.js';
9+
import { serializeAiItemAsk } from '../schemas/aiItemAsk.generated.js';
10+
import { deserializeAiItemAsk } from '../schemas/aiItemAsk.generated.js';
11+
import { serializeAiItemAskTypeField } from '../schemas/aiItemAsk.generated.js';
12+
import { deserializeAiItemAskTypeField } from '../schemas/aiItemAsk.generated.js';
1313
import { serializeAiResponse } from '../schemas/aiResponse.generated.js';
1414
import { deserializeAiResponse } from '../schemas/aiResponse.generated.js';
1515
import { serializeAiTextGen } from '../schemas/aiTextGen.generated.js';
@@ -32,6 +32,8 @@ import { serializeUploadFileRequestBodyAttributesParentField } from '../managers
3232
import { deserializeUploadFileRequestBodyAttributesParentField } from '../managers/uploads.generated.js';
3333
import { serializeAiExtract } from '../schemas/aiExtract.generated.js';
3434
import { deserializeAiExtract } from '../schemas/aiExtract.generated.js';
35+
import { serializeAiItemBase } from '../schemas/aiItemBase.generated.js';
36+
import { deserializeAiItemBase } from '../schemas/aiItemBase.generated.js';
3537
import { serializeAiExtractStructuredResponse } from '../schemas/aiExtractStructuredResponse.generated.js';
3638
import { deserializeAiExtractStructuredResponse } from '../schemas/aiExtractStructuredResponse.generated.js';
3739
import { serializeAiExtractStructured } from '../schemas/aiExtractStructured.generated.js';
@@ -67,8 +69,8 @@ import { FileFull } from '../schemas/fileFull.generated.js';
6769
import { AiResponseFull } from '../schemas/aiResponseFull.generated.js';
6870
import { AiAsk } from '../schemas/aiAsk.generated.js';
6971
import { AiAskModeField } from '../schemas/aiAsk.generated.js';
70-
import { AiItemBase } from '../schemas/aiItemBase.generated.js';
71-
import { AiItemBaseTypeField } from '../schemas/aiItemBase.generated.js';
72+
import { AiItemAsk } from '../schemas/aiItemAsk.generated.js';
73+
import { AiItemAskTypeField } from '../schemas/aiItemAsk.generated.js';
7274
import { AiResponse } from '../schemas/aiResponse.generated.js';
7375
import { AiTextGen } from '../schemas/aiTextGen.generated.js';
7476
import { AiTextGenItemsField } from '../schemas/aiTextGen.generated.js';
@@ -82,6 +84,7 @@ import { UploadFileRequestBody } from '../managers/uploads.generated.js';
8284
import { UploadFileRequestBodyAttributesField } from '../managers/uploads.generated.js';
8385
import { UploadFileRequestBodyAttributesParentField } from '../managers/uploads.generated.js';
8486
import { AiExtract } from '../schemas/aiExtract.generated.js';
87+
import { AiItemBase } from '../schemas/aiItemBase.generated.js';
8588
import { AiExtractStructuredResponse } from '../schemas/aiExtractStructuredResponse.generated.js';
8689
import { AiExtractStructured } from '../schemas/aiExtractStructured.generated.js';
8790
import { AiExtractStructuredFieldsField } from '../schemas/aiExtractStructured.generated.js';
@@ -118,48 +121,48 @@ import { sdIsMap } from '../serialization/json.js';
118121
export const client: BoxClient = getDefaultClient();
119122
test('testAskAISingleItem', async function testAskAISingleItem(): Promise<any> {
120123
const fileToAsk: FileFull = await uploadNewFile();
121-
const response: AiResponseFull = await client.ai.createAiAsk({
124+
const response: undefined | AiResponseFull = await client.ai.createAiAsk({
122125
mode: 'single_item_qa' as AiAskModeField,
123126
prompt: 'which direction sun rises',
124127
items: [
125-
new AiItemBase({
128+
{
126129
id: fileToAsk.id,
127-
type: 'file' as AiItemBaseTypeField,
130+
type: 'file' as AiItemAskTypeField,
128131
content: 'Sun rises in the East',
129-
}),
132+
} satisfies AiItemAsk,
130133
],
131134
} satisfies AiAsk);
132-
if (!(response.answer.includes('East') as boolean)) {
135+
if (!(response!.answer.includes('East') as boolean)) {
133136
throw new Error('Assertion failed');
134137
}
135-
if (!(response.completionReason == 'done')) {
138+
if (!(response!.completionReason == 'done')) {
136139
throw new Error('Assertion failed');
137140
}
138141
await client.files.deleteFileById(fileToAsk.id);
139142
});
140143
test('testAskAIMultipleItems', async function testAskAIMultipleItems(): Promise<any> {
141144
const fileToAsk1: FileFull = await uploadNewFile();
142145
const fileToAsk2: FileFull = await uploadNewFile();
143-
const response: AiResponseFull = await client.ai.createAiAsk({
146+
const response: undefined | AiResponseFull = await client.ai.createAiAsk({
144147
mode: 'multiple_item_qa' as AiAskModeField,
145148
prompt: 'Which direction sun rises?',
146149
items: [
147-
new AiItemBase({
150+
{
148151
id: fileToAsk1.id,
149-
type: 'file' as AiItemBaseTypeField,
152+
type: 'file' as AiItemAskTypeField,
150153
content: 'Earth goes around the sun',
151-
}),
152-
new AiItemBase({
154+
} satisfies AiItemAsk,
155+
{
153156
id: fileToAsk2.id,
154-
type: 'file' as AiItemBaseTypeField,
157+
type: 'file' as AiItemAskTypeField,
155158
content: 'Sun rises in the East in the morning',
156-
}),
159+
} satisfies AiItemAsk,
157160
],
158161
} satisfies AiAsk);
159-
if (!(response.answer.includes('East') as boolean)) {
162+
if (!(response!.answer.includes('East') as boolean)) {
160163
throw new Error('Assertion failed');
161164
}
162-
if (!(response.completionReason == 'done')) {
165+
if (!(response!.completionReason == 'done')) {
163166
throw new Error('Assertion failed');
164167
}
165168
await client.files.deleteFileById(fileToAsk1.id);

0 commit comments

Comments
 (0)