Skip to content

Commit e1ab390

Browse files
authored
Merge pull request #230 from nextcloud/feat/tool-info
Feat: Information Source info in Chat UI
2 parents 05d6f4c + 395b727 commit e1ab390

File tree

11 files changed

+160
-5
lines changed

11 files changed

+160
-5
lines changed

appinfo/info.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Known providers:
6262
6363
More details on how to set this up in the [admin docs](https://docs.nextcloud.com/server/latest/admin_manual/ai/index.html)
6464
]]> </description>
65-
<version>2.4.0</version>
65+
<version>2.5.0</version>
6666
<licence>agpl</licence>
6767
<author>Julien Veyssier</author>
6868
<namespace>Assistant</namespace>

lib/Db/ChattyLLM/Message.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
* @method \void setTimestamp(int $timestamp)
2424
* @method \int getOcpTaskId()
2525
* @method \void setOcpTaskId(int $ocpTaskId)
26+
* @method \string getSources()
27+
* @method \void setSources(string $sources)
2628
*/
2729
class Message extends Entity implements \JsonSerializable {
2830
/** @var int */
@@ -35,6 +37,8 @@ class Message extends Entity implements \JsonSerializable {
3537
protected $timestamp;
3638
/** @var int */
3739
protected $ocpTaskId;
40+
/** @var string */
41+
protected $sources;
3842

3943
public static $columns = [
4044
'id',
@@ -43,6 +47,7 @@ class Message extends Entity implements \JsonSerializable {
4347
'content',
4448
'timestamp',
4549
'ocp_task_id',
50+
'sources',
4651
];
4752
public static $fields = [
4853
'id',
@@ -51,6 +56,7 @@ class Message extends Entity implements \JsonSerializable {
5156
'content',
5257
'timestamp',
5358
'ocpTaskId',
59+
'sources',
5460
];
5561

5662
public function __construct() {
@@ -59,6 +65,7 @@ public function __construct() {
5965
$this->addType('content', Types::STRING);
6066
$this->addType('timestamp', Types::INTEGER);
6167
$this->addType('ocp_task_id', Types::INTEGER);
68+
$this->addType('sources', Types::STRING);
6269
}
6370

6471
#[\ReturnTypeWillChange]
@@ -70,6 +77,7 @@ public function jsonSerialize() {
7077
'content' => $this->content,
7178
'timestamp' => $this->timestamp,
7279
'ocp_task_id' => $this->ocpTaskId,
80+
'sources' => $this->sources,
7381
];
7482
}
7583
}

lib/Listener/BeforeTemplateRenderedListener.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace OCA\Assistant\Listener;
1111

1212
use OCA\Assistant\AppInfo\Application;
13+
use OCA\Assistant\Service\AssistantService;
1314
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
1415
use OCP\AppFramework\Http\TemplateResponse;
1516
use OCP\AppFramework\Services\IInitialState;
@@ -34,6 +35,7 @@ public function __construct(
3435
private IAppConfig $appConfig,
3536
private IInitialState $initialStateService,
3637
private IEventDispatcher $eventDispatcher,
38+
private AssistantService $assistantService,
3739
private ?string $userId,
3840
) {
3941
}
@@ -63,6 +65,7 @@ public function handle(Event $event): void {
6365
$this->initialStateService->provideInitialState('last-target-language', $lastTargetLanguage);
6466
$indexingComplete = $this->appConfig->getValueInt('context_chat', 'last_indexed_time', 0) !== 0;
6567
$this->initialStateService->provideInitialState('contextChatIndexingComplete', $indexingComplete);
68+
$this->initialStateService->provideInitialState('contextAgentToolSources', $this->assistantService->informationSources);
6669
}
6770
if (class_exists(\OCA\Viewer\Event\LoadViewer::class)) {
6871
$this->eventDispatcher->dispatchTyped(new \OCA\Viewer\Event\LoadViewer());

lib/Listener/ChattyLLMTaskListener.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ public function handle(Event $event): void {
6161
$message->setRole('assistant');
6262
$message->setContent(trim($task->getOutput()['output'] ?? ''));
6363
$message->setTimestamp(time());
64+
$sources = json_encode($task->getOutput()['sources'] ?? []);
65+
$message->setSources($sources ? $sources : '[]');
6466
try {
6567
$this->messageMapper->insert($message);
6668
} catch (\OCP\DB\Exception $e) {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
6+
* SPDX-License-Identifier: AGPL-3.0-or-later
7+
*/
8+
9+
namespace OCA\Assistant\Migration;
10+
11+
use Closure;
12+
use OCP\DB\ISchemaWrapper;
13+
use OCP\DB\Types;
14+
use OCP\Migration\IOutput;
15+
use OCP\Migration\SimpleMigrationStep;
16+
17+
class Version020500Date20250425125359 extends SimpleMigrationStep {
18+
19+
/**
20+
* @param IOutput $output
21+
* @param Closure(): ISchemaWrapper $schemaClosure
22+
* @param array $options
23+
* @return null|ISchemaWrapper
24+
*/
25+
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
26+
/** @var ISchemaWrapper $schema */
27+
$schema = $schemaClosure();
28+
$schemaChanged = false;
29+
30+
if ($schema->hasTable('assistant_chat_msgs')) {
31+
$table = $schema->getTable('assistant_chat_msgs');
32+
if (!$table->hasColumn('sources')) {
33+
$table->addColumn('sources', Types::TEXT, [
34+
'notnull' => true,
35+
'default' => '[]',
36+
]);
37+
$schemaChanged = true;
38+
}
39+
}
40+
41+
return $schemaChanged ? $schema : null;
42+
}
43+
}

lib/ResponseDefinitions.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
* content: string,
6565
* timestamp: int,
6666
* ocp_task_id: int,
67+
* sources: string,
6768
* }
6869
*
6970
* @psalm-type AssistantChatAgencyMessage = AssistantChatMessage&array{

lib/Service/AssistantService.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ class AssistantService {
7474
TextToTextTopics::ID => 10,
7575
];
7676

77+
public array $informationSources;
78+
7779
public function __construct(
7880
private ITaskProcessingManager $taskProcessingManager,
7981
private TaskNotificationMapper $taskNotificationMapper,
@@ -86,6 +88,36 @@ public function __construct(
8688
private IConfig $config,
8789
private IShareManager $shareManager,
8890
) {
91+
$this->informationSources = [
92+
'ask_context_chat' => $this->l10n->t('Context Chat'),
93+
'transcribe_file' => $this->l10n->t('Assistant File Transcription'),
94+
'generate_document' => $this->l10n->t('Assistant Document Generation'),
95+
'list_calendars' => $this->l10n->t('Nextcloud Calendar'),
96+
'schedule_event' => $this->l10n->t('Nextcloud Calendar'),
97+
'find_free_time_slot_in_calendar' => $this->l10n->t('Nextcloud Calendar'),
98+
'add_task' => $this->l10n->t('Nextcloud Tasks'),
99+
'find_details_of_current_user' => $this->l10n->t('Nextcloud User Profile'),
100+
'list_decks' => $this->l10n->t('Nextcloud Deck'),
101+
'add_card' => $this->l10n->t('Nextcloud Deck'),
102+
'get_coordinates_for_address' => $this->l10n->t('OpenStreetMap'),
103+
'get_current_weather_for_coordinates' => $this->l10n->t('Norwegian Meteorological Institute Weather Forecast'),
104+
'get_public_transport_route_for_coordinates,' => $this->l10n->t('HERE Public Transport API'),
105+
'get_osm_route,' => $this->l10n->t('OpenStreetMap'),
106+
'get_osm_link,' => $this->l10n->t('OpenStreetMap'),
107+
'get_file_content' => $this->l10n->t('Nextcloud Files'),
108+
'get_folder_tree' => $this->l10n->t('Nextcloud Files'),
109+
'create_public_sharing_link' => $this->l10n->t('Nextcloud Files'),
110+
'send_email' => $this->l10n->t('Nextcloud Mail'),
111+
'get_mail_account_list' => $this->l10n->t('Nextcloud Mail'),
112+
'list_projects,' => $this->l10n->t('OpenProject'),
113+
'list_assignees,' => $this->l10n->t('OpenProject'),
114+
'create_work_package' => $this->l10n->t('OpenProject'),
115+
'list_talk_conversations' => $this->l10n->t('Nextcloud Talk'),
116+
'create_public_conversation' => $this->l10n->t('Nextcloud Talk'),
117+
'send_message_to_conversation' => $this->l10n->t('Nextcloud Talk'),
118+
'list_messages_in_conversation' => $this->l10n->t('Nextcloud Talk'),
119+
'duckduckgo_results_json' => $this->l10n->t('DuckDuckGo Web Search'),
120+
];
89121
}
90122

91123
/**

openapi.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
"role",
5050
"content",
5151
"timestamp",
52-
"ocp_task_id"
52+
"ocp_task_id",
53+
"sources"
5354
],
5455
"properties": {
5556
"id": {
@@ -73,6 +74,9 @@
7374
"ocp_task_id": {
7475
"type": "integer",
7576
"format": "int64"
77+
},
78+
"sources": {
79+
"type": "string"
7680
}
7781
}
7882
},

src/components/ChattyLLM/ChattyLLMInputForm.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export default {
227227
sessionIdToDelete: null,
228228
chatContent: '',
229229
sessions: null,
230-
// [{ id: number, session_id: number, role: string, content: string, timestamp: number }]
230+
// [{ id: number, session_id: number, role: string, content: string, timestamp: number, sources:string }]
231231
messages: [], // null when failed to fetch
232232
messagesAxiosController: null, // for request cancellation
233233
allMessagesLoaded: false,

src/components/ChattyLLM/ConversationBox.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
:delete-loading="loading.messageDelete && message.id === deleteMessageId"
2929
:regenerate-loading="loading.llmGeneration && message.id === regenerateFromId"
3030
:new-message-loading="loading.newHumanMessage && idx === (messages.length - 1)"
31+
:information-source-names="informationSourceNames"
3132
@regenerate="regenerate(message.id)"
3233
@delete="deleteMessage(message.id)" />
3334
<LoadingPlaceholder v-if="loading.llmGeneration" />
@@ -44,6 +45,8 @@ import LoadingPlaceholder from './LoadingPlaceholder.vue'
4445
import Message from './Message.vue'
4546
import NoSession from './NoSession.vue'
4647
48+
import { loadState } from '@nextcloud/initial-state'
49+
4750
export default {
4851
name: 'ConversationBox',
4952
@@ -58,7 +61,7 @@ export default {
5861
},
5962
6063
props: {
61-
// [{ id: number, session_id: number, role: string, content: string, timestamp: number }]
64+
// [{ id: number, session_id: number, role: string, content: string, timestamp: number, sources: string }]
6265
messages: {
6366
type: Array,
6467
default: null,
@@ -82,6 +85,7 @@ export default {
8285
return {
8386
regenerateFromId: null,
8487
deleteMessageId: null,
88+
informationSourceNames: loadState('assistant', 'contextAgentToolSources'),
8589
}
8690
},
8791

0 commit comments

Comments
 (0)