θΏ™ζ˜―indexlocζδΎ›ηš„ζœεŠ‘οΌŒδΈθ¦θΎ“ε…₯任何密码
Skip to content
17 changes: 16 additions & 1 deletion frontend/src/pages/WorkspaceSettings/AgentConfig/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import System from "@/models/system";
import Workspace from "@/models/workspace";
import showToast from "@/utils/toast";
import { castToType } from "@/utils/types";
import { useEffect, useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import AgentLLMSelection from "./AgentLLMSelection";
import Admin from "@/models/admin";
import * as Skeleton from "react-loading-skeleton";
import "react-loading-skeleton/dist/skeleton.css";
import paths from "@/utils/paths";
import useUser from "@/hooks/useUser";
import { BooleanInput } from "@/pages/GeneralSettings/ChatEmbedWidgets/EmbedConfigs/NewEmbedModal/index.jsx";

export default function WorkspaceAgentConfiguration({ workspace }) {
const { user } = useUser();
Expand Down Expand Up @@ -54,6 +55,14 @@ export default function WorkspaceAgentConfiguration({ workspace }) {
data.workspace[key] = castToType(key, value);
}

if (
!Object.prototype.hasOwnProperty.call(
data.workspace,
"useWorkspacePromptForAgents"
)
) {
data.workspace.useWorkspacePromptForAgents = false; // If not present in the form data (checkbox toggled off) - set false
}
const { workspace: updatedWorkspace, message } = await Workspace.update(
workspace.slug,
data.workspace
Expand Down Expand Up @@ -86,6 +95,12 @@ export default function WorkspaceAgentConfiguration({ workspace }) {
workspace={workspace}
setHasChanges={setHasChanges}
/>
<BooleanInput
name="useWorkspacePromptForAgents"
title="Use Workspace System Prompt"
hint="Use System Prompt set in this workspace Chat Settings for @agent requests as well."
defaultValue={workspace.useWorkspacePromptForAgents}
/>
{(!user || user?.role === "admin") && (
<>
{!hasChanges && (
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/utils/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export function castToType(key, value) {
topN: {
cast: (value) => Number(value),
},
useWorkspacePromptForAgents: {
cast: (value) => value === "on" || value === "true" || value === true,
},
};

if (!definitions.hasOwnProperty(key)) return value;
Expand Down
40 changes: 40 additions & 0 deletions server/__tests__/utils/agents/defaults.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* eslint-disable no-undef */
/* eslint-env jest, node */
/* global describe, it, expect */

const path = require("path");
// Ensure STORAGE_DIR is defined so modules that rely on it do not error out in tests.
if (!process.env.STORAGE_DIR) {
process.env.STORAGE_DIR = path.resolve(__dirname, "../../../storage");
}

// Mock MCPCompatibilityLayer to avoid dynamic import issues during unit tests.
jest.mock("../../../utils/MCP", () => {
return function () {
return {
activeMCPServers: async () => [],
};
};
});

const { WORKSPACE_AGENT } = require("../../../utils/agents/defaults");
const Provider = require("../../../utils/agents/aibitat/providers/ai-provider");

describe("WORKSPACE_AGENT.getDefinition system prompt prioritization", () => {
it("uses workspace.openAiPrompt when provided and flag is true", async () => {
const workspace = { openAiPrompt: "Respond only in emoji.", useWorkspacePromptForAgents: true };
const def = await WORKSPACE_AGENT.getDefinition("openai", workspace, null);
expect(def.role).toBe("Respond only in emoji.");
});

it("falls back to Provider.systemPrompt when workspace prompt is absent", async () => {
const workspace = {};
const def = await WORKSPACE_AGENT.getDefinition("openai", workspace, null);
expect(def.role).toBe(Provider.systemPrompt("openai"));
});
it("falls back to Provider.systemPrompt when workspace.openAiPrompt provided but flag is false", async () => {
const workspace = { openAiPrompt: "Respond only in emoji.", useWorkspacePromptForAgents: false };
const def = await WORKSPACE_AGENT.getDefinition("openai", workspace, null);
expect(def.role).toBe(Provider.systemPrompt("openai"));
});
});
11 changes: 9 additions & 2 deletions server/endpoints/api/workspace/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function apiWorkspaceEndpoints(app) {
openAiTemp: 0.7,
openAiHistory: 20,
openAiPrompt: "Custom prompt for responses",
useWorkspacePromptForAgents: false,
queryRefusalResponse: "Custom refusal message",
chatMode: "chat",
topN: 4
Expand All @@ -55,7 +56,8 @@ function apiWorkspaceEndpoints(app) {
"openAiTemp": null,
"lastUpdatedAt": "2023-08-17 00:45:03",
"openAiHistory": 20,
"openAiPrompt": null
"openAiPrompt": null,
"useWorkspacePromptForAgents": false
},
message: 'Workspace created'
}
Expand Down Expand Up @@ -120,6 +122,7 @@ function apiWorkspaceEndpoints(app) {
"lastUpdatedAt": "2023-08-17 00:45:03",
"openAiHistory": 20,
"openAiPrompt": null,
"useWorkspacePromptForAgents": false,
"threads": []
}
],
Expand Down Expand Up @@ -180,6 +183,7 @@ function apiWorkspaceEndpoints(app) {
"lastUpdatedAt": "2023-08-17 00:45:03",
"openAiHistory": 20,
"openAiPrompt": null,
"useWorkspacePromptForAgents": false,
"documents": [],
"threads": []
}
Expand Down Expand Up @@ -292,7 +296,8 @@ function apiWorkspaceEndpoints(app) {
"name": 'Updated Workspace Name',
"openAiTemp": 0.2,
"openAiHistory": 20,
"openAiPrompt": "Respond to all inquires and questions in binary - do not respond in any other format."
"openAiPrompt": "Respond to all inquires and questions in binary - do not respond in any other format.",
"useWorkspacePromptForAgents": false
}
}
}
Expand All @@ -312,6 +317,7 @@ function apiWorkspaceEndpoints(app) {
"lastUpdatedAt": "2023-08-17 00:45:03",
"openAiHistory": 20,
"openAiPrompt": null,
"useWorkspacePromptForAgents": false,
"documents": []
},
message: null,
Expand Down Expand Up @@ -485,6 +491,7 @@ function apiWorkspaceEndpoints(app) {
"lastUpdatedAt": "2023-08-17 00:45:03",
"openAiHistory": 20,
"openAiPrompt": null,
"useWorkspacePromptForAgents": false,
"documents": []
},
message: null,
Expand Down
4 changes: 3 additions & 1 deletion server/models/workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function isNullOrNaN(value) {
* @property {string} agentModel - The agent model of the workspace
* @property {string} queryRefusalResponse - The query refusal response of the workspace
* @property {string} vectorSearchMode - The vector search mode of the workspace
* @property {boolean} useWorkspacePromptForAgents - Should Use Workspace System Prompt For Agent requests as well
*/

const Workspace = {
Expand All @@ -55,9 +56,10 @@ const Workspace = {
"agentModel",
"queryRefusalResponse",
"vectorSearchMode",
"useWorkspacePromptForAgents",
],

validations: {
useWorkspacePromptForAgents: (value) => Boolean(value),
name: (value) => {
// If the name is not provided or is not a string then we will use a default name.
// as the name field is not nullable in the db schema or has a default value.
Expand Down
2 changes: 2 additions & 0 deletions server/prisma/migrations/20250723135715_init/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "workspaces" ADD COLUMN "useWorkspacePromptForAgents" BOOLEAN NOT NULL DEFAULT false;
1 change: 1 addition & 0 deletions server/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ model workspaces {
agentModel String?
queryRefusalResponse String?
vectorSearchMode String? @default("default")
useWorkspacePromptForAgents Boolean @default(false)
workspace_users workspace_users[]
documents workspace_documents[]
workspace_suggested_messages workspace_suggested_messages[]
Expand Down
13 changes: 10 additions & 3 deletions server/swagger/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1691,7 +1691,8 @@
"openAiTemp": null,
"lastUpdatedAt": "2023-08-17 00:45:03",
"openAiHistory": 20,
"openAiPrompt": null
"openAiPrompt": null,
"useWorkspacePromptForAgents": false
},
"message": "Workspace created"
}
Expand Down Expand Up @@ -1732,6 +1733,7 @@
"openAiTemp": 0.7,
"openAiHistory": 20,
"openAiPrompt": "Custom prompt for responses",
"useWorkspacePromptForAgents": false,
"queryRefusalResponse": "Custom refusal message",
"chatMode": "chat",
"topN": 4
Expand Down Expand Up @@ -1765,6 +1767,7 @@
"openAiTemp": null,
"lastUpdatedAt": "2023-08-17 00:45:03",
"openAiHistory": 20,
"useWorkspacePromptForAgents": false,
"openAiPrompt": null,
"threads": []
}
Expand Down Expand Up @@ -1830,6 +1833,7 @@
"lastUpdatedAt": "2023-08-17 00:45:03",
"openAiHistory": 20,
"openAiPrompt": null,
"useWorkspacePromptForAgents": false,
"documents": [],
"threads": []
}
Expand Down Expand Up @@ -1937,6 +1941,7 @@
"lastUpdatedAt": "2023-08-17 00:45:03",
"openAiHistory": 20,
"openAiPrompt": null,
"useWorkspacePromptForAgents": false,
"documents": []
},
"message": null
Expand Down Expand Up @@ -1976,7 +1981,8 @@
"name": "Updated Workspace Name",
"openAiTemp": 0.2,
"openAiHistory": 20,
"openAiPrompt": "Respond to all inquires and questions in binary - do not respond in any other format."
"openAiPrompt": "Respond to all inquires and questions in binary - do not respond in any other format.",
"useWorkspacePromptForAgents": false
}
}
}
Expand Down Expand Up @@ -2114,6 +2120,7 @@
"lastUpdatedAt": "2023-08-17 00:45:03",
"openAiHistory": 20,
"openAiPrompt": null,
"useWorkspacePromptForAgents": false,
"documents": []
},
"message": null
Expand Down Expand Up @@ -4079,4 +4086,4 @@
"BearerAuth": []
}
]
}
}
22 changes: 20 additions & 2 deletions server/utils/agents/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const Provider = require("./aibitat/providers/ai-provider");
const ImportedPlugin = require("./imported");
const { AgentFlows } = require("../agentFlows");
const MCPCompatibilityLayer = require("../MCP");
const { SystemPromptVariables } = require("../../models/systemPromptVariables");

// This is a list of skills that are built-in and default enabled.
const DEFAULT_SKILLS = [
Expand All @@ -23,11 +24,28 @@ const USER_AGENT = {
},
};

/**
* Resolve system prompt from workspace if valid. fallback to provider/static prompt
* @param {Object|null} workspace
* @param {number|null} userId
* @param {string|null} provider
*/
async function resolveSystemPrompt(workspace, userId, provider) {
if (workspace?.useWorkspacePromptForAgents && workspace?.openAiPrompt) {
return await SystemPromptVariables.expandSystemPromptVariables(
workspace.openAiPrompt,
userId
);
} else {
return Provider.systemPrompt(provider);
}
}

const WORKSPACE_AGENT = {
name: "@agent",
getDefinition: async (provider = null) => {
getDefinition: async (provider = null, workspace = null, userId = null) => {
return {
role: Provider.systemPrompt(provider),
role: await resolveSystemPrompt(workspace, userId, provider),
functions: [
...(await agentSkillsFromSystemSettings()),
...ImportedPlugin.activeImportedPlugins(),
Expand Down
22 changes: 7 additions & 15 deletions server/utils/agents/ephemeral.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ const { AgentFlows } = require("../agentFlows");
const { httpSocket } = require("./aibitat/plugins/http-socket.js");
const { WorkspaceChats } = require("../../models/workspaceChats");
const { safeJsonParse } = require("../http");
const {
USER_AGENT,
WORKSPACE_AGENT,
agentSkillsFromSystemSettings,
} = require("./defaults");
const { USER_AGENT, WORKSPACE_AGENT } = require("./defaults");
const { AgentHandler } = require(".");
const {
WorkspaceAgentInvocation,
Expand Down Expand Up @@ -320,17 +316,13 @@ class EphemeralAgentHandler extends AgentHandler {
// Default User agent and workspace agent
this.log(`Attaching user and default agent to Agent cluster.`);
this.aibitat.agent(USER_AGENT.name, await USER_AGENT.getDefinition());
this.aibitat.agent(
WORKSPACE_AGENT.name,
await WORKSPACE_AGENT.getDefinition(this.provider)
const wsAgentDefs = await WORKSPACE_AGENT.getDefinition(
this.provider,
this.#workspace,
this.#userId
);

this.#funcsToLoad = [
...(await agentSkillsFromSystemSettings()),
...ImportedPlugin.activeImportedPlugins(),
...AgentFlows.activeFlowPlugins(),
...(await new MCPCompatibilityLayer().activeMCPServers()),
];
this.aibitat.agent(WORKSPACE_AGENT.name, wsAgentDefs);
this.#funcsToLoad = wsAgentDefs?.functions || [];
}

async init() {
Expand Down
14 changes: 6 additions & 8 deletions server/utils/agents/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -510,15 +510,13 @@ class AgentHandler {
// Default User agent and workspace agent
this.log(`Attaching user and default agent to Agent cluster.`);
this.aibitat.agent(USER_AGENT.name, await USER_AGENT.getDefinition());
this.aibitat.agent(
WORKSPACE_AGENT.name,
await WORKSPACE_AGENT.getDefinition(this.provider)
const wsAgentDefs = await WORKSPACE_AGENT.getDefinition(
this.provider,
this.invocation.workspace,
this.invocation.user_id
);

this.#funcsToLoad = [
...((await USER_AGENT.getDefinition())?.functions || []),
...((await WORKSPACE_AGENT.getDefinition())?.functions || []),
];
this.aibitat.agent(WORKSPACE_AGENT.name, wsAgentDefs);
this.#funcsToLoad = wsAgentDefs?.functions || [];
}

async init() {
Expand Down