Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bfe231486 |
@@ -1,4 +1,3 @@
|
||||
< 3.5.0.beta3-dev: 09a68414804a1447f52e5d60691ba59742cda9ec
|
||||
< 3.5.0.beta2-dev: de8624416a15b3d8e7ad350b083cc1420451ccec
|
||||
< 3.5.0.beta1-dev: bdef136080074a993e7c4f5ca562edc31a8ba756
|
||||
< 3.4.0.beta4-dev: a53719ab8eb071459f215227421b3ea4987e5f87
|
||||
|
||||
@@ -5,6 +5,3 @@ node_modules
|
||||
evals/log
|
||||
evals/cases
|
||||
config/eval-llms.local.yml
|
||||
# this gets rid of search results from ag, ripgrep, etc
|
||||
tokenizers/
|
||||
public/ai-share/highlight.min.js
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ GEM
|
||||
racc
|
||||
prettier_print (1.2.1)
|
||||
racc (1.8.1)
|
||||
rack (3.1.14)
|
||||
rack (3.1.12)
|
||||
rainbow (3.1.1)
|
||||
regexp_parser (2.10.0)
|
||||
rubocop (1.74.0)
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class AdminPluginsShowDiscourseAiAgentsEdit extends DiscourseRoute {
|
||||
async model(params) {
|
||||
const allAgents = this.modelFor(
|
||||
"adminPlugins.show.discourse-ai-agents"
|
||||
);
|
||||
const id = parseInt(params.id, 10);
|
||||
return allAgents.findBy("id", id);
|
||||
}
|
||||
|
||||
setupController(controller, model) {
|
||||
super.setupController(controller, model);
|
||||
controller.set(
|
||||
"allAgents",
|
||||
this.modelFor("adminPlugins.show.discourse-ai-agents")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class DiscourseAiAiAgentsRoute extends DiscourseRoute {
|
||||
model() {
|
||||
return this.store.findAll("ai-agent");
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import SiteSetting from "admin/models/site-setting";
|
||||
|
||||
export default class AdminPluginsShowDiscourseAiFeaturesEdit extends DiscourseRoute {
|
||||
async model(params) {
|
||||
const allFeatures = this.modelFor(
|
||||
"adminPlugins.show.discourse-ai-features"
|
||||
);
|
||||
const id = parseInt(params.id, 10);
|
||||
const currentFeature = allFeatures.find((feature) => feature.id === id);
|
||||
|
||||
const { site_settings } = await ajax("/admin/config/site_settings.json", {
|
||||
data: {
|
||||
filter_area: `ai-features/${currentFeature.ref}`,
|
||||
plugin: "discourse-ai",
|
||||
category: "discourse_ai",
|
||||
},
|
||||
});
|
||||
|
||||
currentFeature.feature_settings = site_settings.map((setting) =>
|
||||
SiteSetting.create(setting)
|
||||
);
|
||||
|
||||
return currentFeature;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import { service } from "@ember/service";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class AdminPluginsShowDiscourseAiFeatures extends DiscourseRoute {
|
||||
@service store;
|
||||
|
||||
async model() {
|
||||
return this.store.findAll("ai-feature");
|
||||
}
|
||||
}
|
||||
+1
-10
@@ -2,17 +2,8 @@ import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class AdminPluginsShowDiscourseAiLlmsEdit extends DiscourseRoute {
|
||||
async model(params) {
|
||||
const id = parseInt(params.id, 10);
|
||||
|
||||
if (id < 0) {
|
||||
// You shouldn't be able to access the edit page
|
||||
// if the model is seeded
|
||||
return this.router.transitionTo(
|
||||
"adminPlugins.show.discourse-ai-llms.index"
|
||||
);
|
||||
}
|
||||
|
||||
const allLlms = this.modelFor("adminPlugins.show.discourse-ai-llms");
|
||||
const id = parseInt(params.id, 10);
|
||||
const record = allLlms.findBy("id", id);
|
||||
record.provider_params = record.provider_params || {};
|
||||
return record;
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class AdminPluginsShowDiscourseAiPersonasEdit extends DiscourseRoute {
|
||||
async model(params) {
|
||||
const allPersonas = this.modelFor(
|
||||
"adminPlugins.show.discourse-ai-personas"
|
||||
);
|
||||
const id = parseInt(params.id, 10);
|
||||
return allPersonas.findBy("id", id);
|
||||
}
|
||||
|
||||
setupController(controller, model) {
|
||||
super.setupController(controller, model);
|
||||
controller.set(
|
||||
"allPersonas",
|
||||
this.modelFor("adminPlugins.show.discourse-ai-personas")
|
||||
);
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -1,16 +1,16 @@
|
||||
import { AUTO_GROUPS } from "discourse/lib/constants";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class AdminPluginsShowDiscourseAiAgentsNew extends DiscourseRoute {
|
||||
export default class AdminPluginsShowDiscourseAiPersonasNew extends DiscourseRoute {
|
||||
async model() {
|
||||
const record = this.store.createRecord("ai-agent");
|
||||
const record = this.store.createRecord("ai-persona");
|
||||
record.set("allowed_group_ids", [AUTO_GROUPS.trust_level_0.id]);
|
||||
record.set("rag_uploads", []);
|
||||
// these match the defaults on the table
|
||||
record.set("rag_chunk_tokens", 374);
|
||||
record.set("rag_chunk_overlap_tokens", 10);
|
||||
record.set("rag_conversation_chunks", 10);
|
||||
record.set("allow_agentl_messages", true);
|
||||
record.set("allow_personal_messages", true);
|
||||
record.set("tool_details", false);
|
||||
return record;
|
||||
}
|
||||
@@ -18,8 +18,8 @@ export default class AdminPluginsShowDiscourseAiAgentsNew extends DiscourseRoute
|
||||
setupController(controller, model) {
|
||||
super.setupController(controller, model);
|
||||
controller.set(
|
||||
"allAgents",
|
||||
this.modelFor("adminPlugins.show.discourse-ai-agents")
|
||||
"allPersonas",
|
||||
this.modelFor("adminPlugins.show.discourse-ai-personas")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class DiscourseAiAiPersonasRoute extends DiscourseRoute {
|
||||
model() {
|
||||
return this.store.findAll("ai-persona");
|
||||
}
|
||||
}
|
||||
+1
-5
@@ -1,10 +1,6 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class DiscourseAiToolsNewRoute extends DiscourseRoute {
|
||||
beforeModel(transition) {
|
||||
this.preset = transition.to.queryParams.presetId || "empty_tool";
|
||||
}
|
||||
|
||||
async model() {
|
||||
return this.store.createRecord("ai-tool");
|
||||
}
|
||||
@@ -12,10 +8,10 @@ export default class DiscourseAiToolsNewRoute extends DiscourseRoute {
|
||||
setupController(controller) {
|
||||
super.setupController(...arguments);
|
||||
const toolsModel = this.modelFor("adminPlugins.show.discourse-ai-tools");
|
||||
|
||||
controller.set("allTools", toolsModel);
|
||||
controller.set("presets", toolsModel.resultSetMeta.presets);
|
||||
controller.set("llms", toolsModel.resultSetMeta.llms);
|
||||
controller.set("settings", toolsModel.resultSetMeta.settings);
|
||||
controller.set("selectedPreset", this.preset);
|
||||
}
|
||||
}
|
||||
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
<AiAgentListEditor
|
||||
@agents={{this.allAgents}}
|
||||
@currentAgent={{this.model}}
|
||||
/>
|
||||
-1
@@ -1 +0,0 @@
|
||||
<AiAgentListEditor @agents={{this.model}} />
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
<AiAgentListEditor
|
||||
@agents={{this.allAgents}}
|
||||
@currentAgent={{this.model}}
|
||||
/>
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
import RouteTemplate from "ember-route-template";
|
||||
import BackButton from "discourse/components/back-button";
|
||||
import SiteSettingComponent from "admin/components/site-setting";
|
||||
|
||||
export default RouteTemplate(
|
||||
<template>
|
||||
<BackButton
|
||||
@route="adminPlugins.show.discourse-ai-features"
|
||||
@label="discourse_ai.features.back"
|
||||
/>
|
||||
<section class="ai-feature-editor__header">
|
||||
<h2>{{@model.name}}</h2>
|
||||
<p>{{@model.description}}</p>
|
||||
</section>
|
||||
|
||||
<section class="ai-feature-editor">
|
||||
{{#each @model.feature_settings as |setting|}}
|
||||
<div>
|
||||
<SiteSettingComponent @setting={{setting}} />
|
||||
</div>
|
||||
{{/each}}
|
||||
</section>
|
||||
</template>
|
||||
);
|
||||
-156
@@ -1,156 +0,0 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { service } from "@ember/service";
|
||||
import RouteTemplate from "ember-route-template";
|
||||
import { gt } from "truth-helpers";
|
||||
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DPageSubheader from "discourse/components/d-page-subheader";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default RouteTemplate(
|
||||
class extends Component {
|
||||
@service adminPluginNavManager;
|
||||
|
||||
get tableHeaders() {
|
||||
const prefix = "discourse_ai.features.list.header";
|
||||
return [
|
||||
i18n(`${prefix}.name`),
|
||||
i18n(`${prefix}.agent`),
|
||||
i18n(`${prefix}.groups`),
|
||||
"",
|
||||
];
|
||||
}
|
||||
|
||||
get configuredFeatures() {
|
||||
return this.args.model.filter(
|
||||
(feature) => feature.enable_setting.value === true
|
||||
);
|
||||
}
|
||||
|
||||
get unconfiguredFeatures() {
|
||||
return this.args.model.filter(
|
||||
(feature) => feature.enable_setting.value === false
|
||||
);
|
||||
}
|
||||
|
||||
<template>
|
||||
<DBreadcrumbsItem
|
||||
@path="/admin/plugins/{{this.adminPluginNavManager.currentPlugin.name}}/ai-features"
|
||||
@label={{i18n "discourse_ai.features.short_title"}}
|
||||
/>
|
||||
<section class="ai-feature-list admin-detail">
|
||||
<DPageSubheader
|
||||
@titleLabel={{i18n "discourse_ai.features.short_title"}}
|
||||
@descriptionLabel={{i18n "discourse_ai.features.description"}}
|
||||
@learnMoreUrl="todo"
|
||||
/>
|
||||
|
||||
{{#if (gt this.configuredFeatures.length 0)}}
|
||||
<div class="ai-feature-list__configured-features">
|
||||
<h3>{{i18n "discourse_ai.features.list.configured_features"}}</h3>
|
||||
|
||||
<table class="d-admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{{#each this.tableHeaders as |header|}}
|
||||
<th>{{header}}</th>
|
||||
{{/each}}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{#each this.configuredFeatures as |feature|}}
|
||||
<tr
|
||||
class="ai-feature-list__row d-admin-row__content"
|
||||
data-feature-name={{feature.name}}
|
||||
>
|
||||
<td class="d-admin-row__overview ai-feature-list__row-item">
|
||||
<span class="ai-feature-list__row-item-name">
|
||||
<strong>
|
||||
{{feature.name}}
|
||||
</strong>
|
||||
</span>
|
||||
<span class="ai-feature-list__row-item-description">
|
||||
{{feature.description}}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
class="d-admin-row__detail ai-feature-list__row-item ai-feature-list__agent"
|
||||
>
|
||||
<DButton
|
||||
class="btn-flat btn-small ai-feature-list__row-item-agent"
|
||||
@translatedLabel={{feature.agent.name}}
|
||||
@route="adminPlugins.show.discourse-ai-agents.edit"
|
||||
@routeModels={{feature.agent.id}}
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
class="d-admin-row__detail ai-feature-list__row-item ai-feature-list__groups"
|
||||
>
|
||||
{{#if (gt feature.agent.allowed_groups.length 0)}}
|
||||
<ul class="ai-feature-list__row-item-groups">
|
||||
{{#each feature.agent.allowed_groups as |group|}}
|
||||
<li>{{group.name}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td class="d-admin-row_controls">
|
||||
<DButton
|
||||
class="btn-small edit"
|
||||
@label="discourse_ai.features.list.edit"
|
||||
@route="adminPlugins.show.discourse-ai-features.edit"
|
||||
@routeModels={{feature.id}}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if (gt this.unconfiguredFeatures.length 0)}}
|
||||
<div class="ai-feature-list__unconfigured-features">
|
||||
<h3>{{i18n "discourse_ai.features.list.unconfigured_features"}}</h3>
|
||||
|
||||
<table class="d-admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{i18n "discourse_ai.features.list.header.name"}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{#each this.unconfiguredFeatures as |feature|}}
|
||||
<tr class="ai-feature-list__row d-admin-row__content">
|
||||
<td class="d-admin-row__overview ai-feature-list__row-item">
|
||||
<span class="ai-feature-list__row-item-name">
|
||||
<strong>
|
||||
{{feature.name}}
|
||||
</strong>
|
||||
</span>
|
||||
<span class="ai-feature-list__row-item-description">
|
||||
{{feature.description}}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="d-admin-row_controls">
|
||||
<DButton
|
||||
class="btn-small"
|
||||
@label="discourse_ai.features.list.set_up"
|
||||
@route="adminPlugins.show.discourse-ai-features.edit"
|
||||
@routeModels={{feature.id}}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
</template>
|
||||
}
|
||||
);
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
<AiPersonaListEditor
|
||||
@personas={{this.allPersonas}}
|
||||
@currentPersona={{this.model}}
|
||||
/>
|
||||
+1
@@ -0,0 +1 @@
|
||||
<AiPersonaListEditor @personas={{this.model}} />
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
<AiPersonaListEditor
|
||||
@personas={{this.allPersonas}}
|
||||
@currentPersona={{this.model}}
|
||||
/>
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<section class="ai-agent-tool-editor__current admin-detail pull-left">
|
||||
<section class="ai-persona-tool-editor__current admin-detail pull-left">
|
||||
<AiToolEditor
|
||||
@tools={{this.allTools}}
|
||||
@model={{this.model}}
|
||||
|
||||
+1
-2
@@ -1,10 +1,9 @@
|
||||
<section class="ai-agent-tool-editor__current admin-detail pull-left">
|
||||
<section class="ai-persona-tool-editor__current admin-detail pull-left">
|
||||
<AiToolEditor
|
||||
@tools={{this.allTools}}
|
||||
@model={{this.model}}
|
||||
@presets={{this.presets}}
|
||||
@llms={{this.llms}}
|
||||
@settings={{this.settings}}
|
||||
@selectedPreset={{this.selectedPreset}}
|
||||
/>
|
||||
</section>
|
||||
@@ -1,36 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module DiscourseAi
|
||||
module Admin
|
||||
class AiFeaturesController < ::Admin::AdminController
|
||||
requires_plugin ::DiscourseAi::PLUGIN_NAME
|
||||
|
||||
def index
|
||||
render json: serialize_features(DiscourseAi::Features.features)
|
||||
end
|
||||
|
||||
def edit
|
||||
raise Discourse::InvalidParameters.new(:id) if params[:id].blank?
|
||||
render json: serialize_feature(DiscourseAi::Features.find_feature_by_id(params[:id].to_i))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def serialize_features(features)
|
||||
features.map { |feature| feature.merge(agent: serialize_agent(feature[:agent])) }
|
||||
end
|
||||
|
||||
def serialize_feature(feature)
|
||||
return nil if feature.blank?
|
||||
|
||||
feature.merge(agent: serialize_agent(feature[:agent]))
|
||||
end
|
||||
|
||||
def serialize_agent(agent)
|
||||
return nil if agent.blank?
|
||||
|
||||
serialize_data(agent, AiFeaturesAgentSerializer, root: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -157,13 +157,9 @@ module DiscourseAi
|
||||
:provider,
|
||||
:tokenizer,
|
||||
:max_prompt_tokens,
|
||||
:max_output_tokens,
|
||||
:api_key,
|
||||
:enabled_chat_bot,
|
||||
:vision_enabled,
|
||||
:input_cost,
|
||||
:cached_input_cost,
|
||||
:output_cost,
|
||||
)
|
||||
|
||||
provider = updating ? updating.provider : permitted[:provider]
|
||||
|
||||
+37
-63
@@ -2,20 +2,20 @@
|
||||
|
||||
module DiscourseAi
|
||||
module Admin
|
||||
class AiAgentsController < ::Admin::AdminController
|
||||
class AiPersonasController < ::Admin::AdminController
|
||||
requires_plugin ::DiscourseAi::PLUGIN_NAME
|
||||
|
||||
before_action :find_ai_agent, only: %i[edit update destroy create_user]
|
||||
before_action :find_ai_persona, only: %i[edit update destroy create_user]
|
||||
|
||||
def index
|
||||
ai_agents =
|
||||
AiAgent.ordered.map do |agent|
|
||||
ai_personas =
|
||||
AiPersona.ordered.map do |persona|
|
||||
# we use a special serializer here cause names and descriptions are
|
||||
# localized for system agents
|
||||
LocalizedAiAgentSerializer.new(agent, root: false)
|
||||
# localized for system personas
|
||||
LocalizedAiPersonaSerializer.new(persona, root: false)
|
||||
end
|
||||
tools =
|
||||
DiscourseAi::Agents::Agent.all_available_tools.map do |tool|
|
||||
DiscourseAi::Personas::Persona.all_available_tools.map do |tool|
|
||||
AiToolSerializer.new(tool, root: false)
|
||||
end
|
||||
AiTool
|
||||
@@ -36,7 +36,7 @@ module DiscourseAi
|
||||
allowed_seeded_llm_ids: SiteSetting.ai_bot_allowed_seeded_models_map,
|
||||
)
|
||||
render json: {
|
||||
ai_agents: ai_agents,
|
||||
ai_personas: ai_personas,
|
||||
meta: {
|
||||
tools: tools,
|
||||
llms: llms,
|
||||
@@ -51,55 +51,55 @@ module DiscourseAi
|
||||
end
|
||||
|
||||
def edit
|
||||
render json: LocalizedAiAgentSerializer.new(@ai_agent)
|
||||
render json: LocalizedAiPersonaSerializer.new(@ai_persona)
|
||||
end
|
||||
|
||||
def create
|
||||
ai_agent = AiAgent.new(ai_agent_params.except(:rag_uploads))
|
||||
if ai_agent.save
|
||||
RagDocumentFragment.link_target_and_uploads(ai_agent, attached_upload_ids)
|
||||
ai_persona = AiPersona.new(ai_persona_params.except(:rag_uploads))
|
||||
if ai_persona.save
|
||||
RagDocumentFragment.link_target_and_uploads(ai_persona, attached_upload_ids)
|
||||
|
||||
render json: {
|
||||
ai_agent: LocalizedAiAgentSerializer.new(ai_agent, root: false),
|
||||
ai_persona: LocalizedAiPersonaSerializer.new(ai_persona, root: false),
|
||||
},
|
||||
status: :created
|
||||
else
|
||||
render_json_error ai_agent
|
||||
render_json_error ai_persona
|
||||
end
|
||||
end
|
||||
|
||||
def create_user
|
||||
user = @ai_agent.create_user!
|
||||
user = @ai_persona.create_user!
|
||||
render json: BasicUserSerializer.new(user, root: "user")
|
||||
end
|
||||
|
||||
def update
|
||||
if @ai_agent.update(ai_agent_params.except(:rag_uploads))
|
||||
RagDocumentFragment.update_target_uploads(@ai_agent, attached_upload_ids)
|
||||
if @ai_persona.update(ai_persona_params.except(:rag_uploads))
|
||||
RagDocumentFragment.update_target_uploads(@ai_persona, attached_upload_ids)
|
||||
|
||||
render json: LocalizedAiAgentSerializer.new(@ai_agent, root: false)
|
||||
render json: LocalizedAiPersonaSerializer.new(@ai_persona, root: false)
|
||||
else
|
||||
render_json_error @ai_agent
|
||||
render_json_error @ai_persona
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @ai_agent.destroy
|
||||
if @ai_persona.destroy
|
||||
head :no_content
|
||||
else
|
||||
render_json_error @ai_agent
|
||||
render_json_error @ai_persona
|
||||
end
|
||||
end
|
||||
|
||||
def stream_reply
|
||||
agent =
|
||||
AiAgent.find_by(name: params[:agent_name]) ||
|
||||
AiAgent.find_by(id: params[:agent_id])
|
||||
return render_json_error(I18n.t("discourse_ai.errors.agent_not_found")) if agent.nil?
|
||||
persona =
|
||||
AiPersona.find_by(name: params[:persona_name]) ||
|
||||
AiPersona.find_by(id: params[:persona_id])
|
||||
return render_json_error(I18n.t("discourse_ai.errors.persona_not_found")) if persona.nil?
|
||||
|
||||
return render_json_error(I18n.t("discourse_ai.errors.agent_disabled")) if !agent.enabled
|
||||
return render_json_error(I18n.t("discourse_ai.errors.persona_disabled")) if !persona.enabled
|
||||
|
||||
if agent.default_llm.blank?
|
||||
if persona.default_llm.blank?
|
||||
return render_json_error(I18n.t("discourse_ai.errors.no_default_llm"))
|
||||
end
|
||||
|
||||
@@ -107,8 +107,8 @@ module DiscourseAi
|
||||
return render_json_error(I18n.t("discourse_ai.errors.no_query_specified"))
|
||||
end
|
||||
|
||||
if !agent.user_id
|
||||
return render_json_error(I18n.t("discourse_ai.errors.no_user_for_agent"))
|
||||
if !persona.user_id
|
||||
return render_json_error(I18n.t("discourse_ai.errors.no_user_for_persona"))
|
||||
end
|
||||
|
||||
if !params[:username] && !params[:user_unique_id]
|
||||
@@ -142,7 +142,7 @@ module DiscourseAi
|
||||
|
||||
DiscourseAi::AiBot::ResponseHttpStreamer.queue_streamed_reply(
|
||||
io: io,
|
||||
agent: agent,
|
||||
persona: persona,
|
||||
user: user,
|
||||
topic: topic,
|
||||
query: params[:query].to_s,
|
||||
@@ -178,17 +178,17 @@ module DiscourseAi
|
||||
end
|
||||
end
|
||||
|
||||
def find_ai_agent
|
||||
@ai_agent = AiAgent.find(params[:id])
|
||||
def find_ai_persona
|
||||
@ai_persona = AiPersona.find(params[:id])
|
||||
end
|
||||
|
||||
def attached_upload_ids
|
||||
ai_agent_params[:rag_uploads].to_a.map { |h| h[:id] }
|
||||
ai_persona_params[:rag_uploads].to_a.map { |h| h[:id] }
|
||||
end
|
||||
|
||||
def ai_agent_params
|
||||
def ai_persona_params
|
||||
permitted =
|
||||
params.require(:ai_agent).permit(
|
||||
params.require(:ai_persona).permit(
|
||||
:name,
|
||||
:description,
|
||||
:enabled,
|
||||
@@ -209,7 +209,7 @@ module DiscourseAi
|
||||
:allow_chat_channel_mentions,
|
||||
:allow_chat_direct_messages,
|
||||
:allow_topic_mentions,
|
||||
:allow_agentl_messages,
|
||||
:allow_personal_messages,
|
||||
:tool_details,
|
||||
:forced_tool_count,
|
||||
:force_default_llm,
|
||||
@@ -217,18 +217,10 @@ module DiscourseAi
|
||||
rag_uploads: [:id],
|
||||
)
|
||||
|
||||
if tools = params.dig(:ai_agent, :tools)
|
||||
if tools = params.dig(:ai_persona, :tools)
|
||||
permitted[:tools] = permit_tools(tools)
|
||||
end
|
||||
|
||||
if response_format = params.dig(:ai_agent, :response_format)
|
||||
permitted[:response_format] = permit_response_format(response_format)
|
||||
end
|
||||
|
||||
if examples = params.dig(:ai_agent, :examples)
|
||||
permitted[:examples] = permit_examples(examples)
|
||||
end
|
||||
|
||||
permitted
|
||||
end
|
||||
|
||||
@@ -243,24 +235,6 @@ module DiscourseAi
|
||||
[tool, options, !!force_tool]
|
||||
end
|
||||
end
|
||||
|
||||
def permit_response_format(response_format)
|
||||
return [] if !response_format.is_a?(Array)
|
||||
|
||||
response_format.map do |element|
|
||||
if element && element.is_a?(ActionController::Parameters)
|
||||
element.permit!
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def permit_examples(examples)
|
||||
return [] if !examples.is_a?(Array)
|
||||
|
||||
examples.map { |example_arr| example_arr.take(2).map(&:to_s) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -50,7 +50,7 @@ module DiscourseAi
|
||||
)
|
||||
end
|
||||
|
||||
SiteSetting.set_and_log("ai_spam_detection_enabled", is_enabled, current_user)
|
||||
SiteSetting.ai_spam_detection_enabled = is_enabled
|
||||
end
|
||||
|
||||
render json: AiSpamSerializer.new(spam_config, root: false)
|
||||
|
||||
@@ -55,7 +55,7 @@ module DiscourseAi
|
||||
# we need an llm so we have a tokenizer
|
||||
# but will do without if none is available
|
||||
llm = LlmModel.first&.to_llm
|
||||
runner = @ai_tool.runner(parameters, llm: llm, bot_user: current_user)
|
||||
runner = @ai_tool.runner(parameters, llm: llm, bot_user: current_user, context: {})
|
||||
result = runner.invoke
|
||||
|
||||
if result.is_a?(Hash) && result[:error]
|
||||
|
||||
@@ -6,8 +6,8 @@ module DiscourseAi
|
||||
requires_plugin ::DiscourseAi::PLUGIN_NAME
|
||||
|
||||
def indexing_status_check
|
||||
if params[:target_type] == "AiAgent"
|
||||
@target = AiAgent.find(params[:target_id])
|
||||
if params[:target_type] == "AiPersona"
|
||||
@target = AiPersona.find(params[:target_id])
|
||||
elsif params[:target_type] == "AiTool"
|
||||
@target = AiTool.find(params[:target_id])
|
||||
else
|
||||
|
||||
@@ -42,21 +42,6 @@ module DiscourseAi
|
||||
<style>
|
||||
#{artifact.css}
|
||||
</style>
|
||||
<script>
|
||||
window._discourse_user_data = {
|
||||
#{current_user ? "username: #{current_user.username.to_json}" : "username: null"}
|
||||
};
|
||||
window.discourseArtifactReady = new Promise(resolve => {
|
||||
window._resolveArtifactData = resolve;
|
||||
});
|
||||
window.addEventListener('message', function(event) {
|
||||
if (event.data && event.data.type === 'discourse-artifact-data') {
|
||||
window.discourseArtifactData = event.data.dataset || {};
|
||||
Object.assign(window.discourseArtifactData, window._discourse_user_data);
|
||||
window._resolveArtifactData(window.discourseArtifactData);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
#{artifact.html}
|
||||
@@ -89,19 +74,6 @@ module DiscourseAi
|
||||
</head>
|
||||
<body>
|
||||
<iframe sandbox="allow-scripts allow-forms" height="100%" width="100%" srcdoc="#{ERB::Util.html_escape(untrusted_html)}" frameborder="0"></iframe>
|
||||
<script>
|
||||
document.querySelector('iframe').addEventListener('load', function() {
|
||||
try {
|
||||
const iframeWindow = this.contentWindow;
|
||||
const message = { type: 'discourse-artifact-data', dataset: {} };
|
||||
|
||||
if (window.frameElement && window.frameElement.dataset) {
|
||||
Object.assign(message.dataset, window.frameElement.dataset);
|
||||
}
|
||||
iframeWindow.postMessage(message, '*');
|
||||
} catch (e) { console.error('Error passing data to artifact:', e); }
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
@@ -46,17 +46,17 @@ module DiscourseAi
|
||||
end
|
||||
|
||||
def discover
|
||||
ai_agent =
|
||||
AiAgent
|
||||
.all_agents(enabled_only: false)
|
||||
.find { |agent| agent.id == SiteSetting.ai_bot_discover_agent.to_i }
|
||||
ai_persona =
|
||||
AiPersona.all_personas.find do |persona|
|
||||
persona.id == SiteSetting.ai_bot_discover_persona.to_i
|
||||
end
|
||||
|
||||
if ai_agent.nil? || !current_user.in_any_groups?(ai_agent.allowed_group_ids.to_a)
|
||||
if ai_persona.nil? || !current_user.in_any_groups?(ai_persona.allowed_group_ids.to_a)
|
||||
raise Discourse::InvalidAccess.new
|
||||
end
|
||||
|
||||
if ai_agent.default_llm_id.blank?
|
||||
render_json_error "Discover agent is missing a default LLM model.", status: 503
|
||||
if ai_persona.default_llm_id.blank?
|
||||
render_json_error "Discover persona is missing a default LLM model.", status: 503
|
||||
return
|
||||
end
|
||||
|
||||
@@ -69,40 +69,6 @@ module DiscourseAi
|
||||
|
||||
render json: {}, status: 200
|
||||
end
|
||||
|
||||
def discover_continue_convo
|
||||
raise Discourse::InvalidParameters.new("user_id") if !params[:user_id]
|
||||
raise Discourse::InvalidParameters.new("query") if !params[:query]
|
||||
raise Discourse::InvalidParameters.new("context") if !params[:context]
|
||||
|
||||
user = User.find(params[:user_id])
|
||||
|
||||
bot_user_id = AiAgent.find_by(id: SiteSetting.ai_bot_discover_agent).user_id
|
||||
bot_username = User.find_by(id: bot_user_id).username
|
||||
|
||||
query = params[:query]
|
||||
context = "[quote]\n#{params[:context]}\n[/quote]"
|
||||
|
||||
post =
|
||||
PostCreator.create!(
|
||||
user,
|
||||
title:
|
||||
I18n.t("discourse_ai.ai_bot.discoveries.continue_conversation.title", query: query),
|
||||
raw:
|
||||
I18n.t(
|
||||
"discourse_ai.ai_bot.discoveries.continue_conversation.raw",
|
||||
query: query,
|
||||
context: context,
|
||||
),
|
||||
archetype: Archetype.private_message,
|
||||
target_usernames: bot_username,
|
||||
skip_validations: true,
|
||||
)
|
||||
|
||||
render json: success_json.merge(topic_id: post.topic_id)
|
||||
rescue StandardError => e
|
||||
render json: failed_json.merge(errors: [e.message]), status: 422
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user