Skip to content

Commit bb8863b

Browse files
committed
Support files specified in history by task id directly as needed for context agent
Signed-off-by: Lukas Schaefer <lukas@lschaefer.xyz>
1 parent a173a2c commit bb8863b

5 files changed

Lines changed: 39 additions & 19 deletions

File tree

lib/Service/OpenAiAPIService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ private function buildChatCompletionRequestParams(
734734
$content = [];
735735
foreach ($message['content'] as $item) {
736736
if ($item['type'] === 'file') {
737-
$content = array_merge($content, $this->openAiFileService->buildFileContentFromId($item['file_id'], $userId));
737+
$content = array_merge($content, $this->openAiFileService->buildFileContentFromId($item['file_id'], $userId, $item['ocp_task_id'] ?? null));
738738
} else {
739739
$content[] = $item;
740740
}

lib/Service/OpenAiFileService.php

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use OCP\IL10N;
1717
use OCP\TaskProcessing\Exception\ProcessingException;
1818
use OCP\TaskProcessing\Exception\UserFacingProcessingException;
19+
use OCP\TaskProcessing\IManager as ITaskProcessingManager;
1920
use Psr\Log\LoggerInterface;
2021
use RuntimeException;
2122

@@ -73,6 +74,7 @@ public function __construct(
7374
private OpenAiSettingsService $openAiSettingsService,
7475
private IRootFolder $rootFolder,
7576
private LoggerInterface $logger,
77+
private ITaskProcessingManager $taskProcessingManager,
7678
) {
7779
}
7880

@@ -81,13 +83,29 @@ public function __construct(
8183
*
8284
* @param int $fileId The ID of the file to build content from.
8385
* @param string $userId The user ID.
86+
* @param ?int $taskId The ID of the task
8487
* @return list<array<string, mixed>> Content parts suitable for OpenAI chat message content.
8588
* @throws ProcessingException
8689
* @throws UserFacingProcessingException
8790
*/
88-
public function buildFileContentFromId(int $fileId, string $userId): array {
89-
$userFolder = $this->rootFolder->getUserFolder($userId);
90-
$file = $userFolder->getFirstNodeById($fileId);
91+
public function buildFileContentFromId(int $fileId, string $userId, ?int $taskId): array {
92+
$file = null;
93+
if ($taskId !== null) {
94+
$task = $this->taskProcessingManager->getUserTask($taskId, $userId);
95+
$files = $this->taskProcessingManager->extractFileIdsFromTask($task);
96+
97+
if (array_search($fileId, $files, true) === false) {
98+
throw new ProcessingException('File does not exist');
99+
}
100+
$file = $this->rootFolder->getFirstNodeById($fileId);
101+
102+
if ($file === null) {
103+
$file = $this->rootFolder->getFirstNodeByIdInPath($fileId, '/' . $this->rootFolder->getAppDataDirectoryName() . '/');
104+
}
105+
} else {
106+
$userFolder = $this->rootFolder->getUserFolder($userId);
107+
$file = $userFolder->getFirstNodeById($fileId);
108+
}
91109
return $this->buildFileContentFromFile($file);
92110
}
93111

@@ -114,26 +132,30 @@ public function buildFileContentFromFile(?File $file): array {
114132
}
115133

116134
$fileType = $file->getMimeType();
135+
// Backup incase the file does not have an extension
136+
if ($fileType === 'application/octet-stream') {
137+
$fileType = mime_content_type($file->fopen('rb'));
138+
}
117139
if (str_starts_with($fileType, 'image/')) {
118-
return $this->buildImageContent($file);
140+
return $this->buildImageContent($file, $fileType);
119141
// OpenAI only supports this for very specific models and support is not that common
120142
} elseif (str_starts_with($fileType, 'audio/')) {
121-
return $this->buildAudioContent($file);
143+
return $this->buildAudioContent($file, $fileType);
122144
// OpenAI does not currently support video attachments
123145
} elseif (str_starts_with($fileType, 'video/')) {
124-
return $this->buildVideoContent($file);
146+
return $this->buildVideoContent($file, $fileType);
125147
} elseif ($fileType === 'application/pdf') {
126-
return $this->buildDocumentContent($file);
148+
return $this->buildDocumentContent($file, $fileType);
127149
} else {
128-
return $this->buildTextContent($file);
150+
return $this->buildTextContent($file, $fileType);
129151
}
130152
}
131153

132154

133155
/**
134156
* @return list<array{type: string, image_url: array{url: string}}>
135157
*/
136-
private function buildImageContent(File $file): array {
158+
private function buildImageContent(File $file, string $fileType): array {
137159
if (!$this->openAiSettingsService->getMultimodalImageEnabled()) {
138160
throw new UserFacingProcessingException(
139161
'Image attachments are disabled',
@@ -142,7 +164,6 @@ private function buildImageContent(File $file): array {
142164
$this->l10n->t('Image attachments are unsupported.'),
143165
);
144166
}
145-
$fileType = $file->getMimeType();
146167
if ($this->isUsingOpenAi() && !in_array($fileType, self::VALID_IMAGE_MIME_TYPES, true)) {
147168
throw new UserFacingProcessingException(
148169
'Invalid input file type for OpenAI ' . $fileType,
@@ -162,7 +183,7 @@ private function buildImageContent(File $file): array {
162183
/**
163184
* @return list<array{type: string, input_audio: array{data: string, format: string}}>
164185
*/
165-
private function buildAudioContent(File $file): array {
186+
private function buildAudioContent(File $file, string $fileType): array {
166187
if (!$this->openAiSettingsService->getMultimodalAudioEnabled()) {
167188
throw new UserFacingProcessingException(
168189
'Audio attachments are disabled',
@@ -171,7 +192,6 @@ private function buildAudioContent(File $file): array {
171192
$this->l10n->t('Audio attachments are unsupported.'),
172193
);
173194
}
174-
$fileType = $file->getMimeType();
175195

176196
if (!array_key_exists($fileType, self::SUPPORTED_INPUT_AUDIO_FORMATS)) {
177197
throw new UserFacingProcessingException(
@@ -194,7 +214,7 @@ private function buildAudioContent(File $file): array {
194214
/**
195215
* @return list<array{type: string, video_url: array{url: string}}>
196216
*/
197-
private function buildVideoContent(File $file): array {
217+
private function buildVideoContent(File $file, string $fileType): array {
198218
if (!$this->openAiSettingsService->getMultimodalVideoEnabled()) {
199219
throw new UserFacingProcessingException(
200220
'Video attachments are disabled',
@@ -203,7 +223,6 @@ private function buildVideoContent(File $file): array {
203223
$this->l10n->t('Video attachments are unsupported.'),
204224
);
205225
}
206-
$fileType = $file->getMimeType();
207226
return [[
208227
'type' => 'video_url',
209228
'video_url' => [
@@ -215,7 +234,7 @@ private function buildVideoContent(File $file): array {
215234
/**
216235
* @return list<array{type: string, file: array{filename: string, file_data: string}}|array{type: string, image_url: array{url: string}}>
217236
*/
218-
private function buildDocumentContent(File $file): array {
237+
private function buildDocumentContent(File $file, string $fileType): array {
219238
if (!$this->openAiSettingsService->getMultimodalDocumentEnabled()) {
220239
// Fallback to image if documents are not supported
221240
if ($this->openAiSettingsService->getMultimodalImageEnabled()) {
@@ -228,7 +247,6 @@ private function buildDocumentContent(File $file): array {
228247
$this->l10n->t('Document attachments are unsupported.'),
229248
);
230249
}
231-
$fileType = $file->getMimeType();
232250
return [[
233251
'type' => 'file',
234252
'file' => [
@@ -241,8 +259,7 @@ private function buildDocumentContent(File $file): array {
241259
/**
242260
* @return list<array{type: string, text: string}>
243261
*/
244-
private function buildTextContent(File $file): array {
245-
$fileType = $file->getMimeType();
262+
private function buildTextContent(File $file, string $fileType): array {
246263
// Sanity check that this isn't a binary
247264
if (!str_starts_with($fileType, 'text/') && !in_array($fileType, self::VALID_TEXT_MIME_TYPES, true)) {
248265
throw new UserFacingProcessingException(

tests/unit/Providers/OpenAiProviderTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ protected function setUp(): void {
103103
$this->openAiSettingsService,
104104
$this->createMock(\OCP\Files\IRootFolder::class),
105105
$this->createMock(\Psr\Log\LoggerInterface::class),
106+
$this->createMock(\OCP\TaskProcessing\IManager::class),
106107
),
107108
$this->createMock(\OCP\Notification\IManager::class),
108109
\OCP\Server::get(QuotaRuleService::class),

tests/unit/Quota/QuotaTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ protected function setUp(): void {
9393
$this->openAiSettingsService,
9494
$this->createMock(\OCP\Files\IRootFolder::class),
9595
$this->createMock(LoggerInterface::class),
96+
$this->createMock(\OCP\TaskProcessing\IManager::class),
9697
),
9798
$this->notificationManager,
9899
\OCP\Server::get(QuotaRuleService::class),

tests/unit/Service/ServiceOverrideTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ protected function setUp(): void {
9696
$this->openAiSettingsService,
9797
$this->createMock(\OCP\Files\IRootFolder::class),
9898
$this->createMock(\Psr\Log\LoggerInterface::class),
99+
$this->createMock(\OCP\TaskProcessing\IManager::class),
99100
),
100101
$this->createMock(\OCP\Notification\IManager::class),
101102
\OCP\Server::get(QuotaRuleService::class),

0 commit comments

Comments
 (0)