feat(ai-agent): Implement AI Agent service with configuration, registration, and health check functionality

This commit is contained in:
Nawaz Dhandala 2025-12-24 15:24:47 +00:00
parent 51e9e2d95b
commit 1a2acbf12d
No known key found for this signature in database
GPG key ID: 96C5DCA24769DBCA
18 changed files with 651 additions and 5 deletions

40
AIAgent/Config.ts Normal file
View file

@ -0,0 +1,40 @@
import URL from "Common/Types/API/URL";
import ObjectID from "Common/Types/ObjectID";
import logger from "Common/Server/Utils/Logger";
import Port from "Common/Types/Port";
if (!process.env["ONEUPTIME_URL"]) {
logger.error("ONEUPTIME_URL is not set");
process.exit();
}
export let ONEUPTIME_URL: URL = URL.fromString(
process.env["ONEUPTIME_URL"] || "https://oneuptime.com",
);
// If the URL does not have the ai-agent-ingest path, add it.
if (
!ONEUPTIME_URL.toString().endsWith("ai-agent-ingest") &&
!ONEUPTIME_URL.toString().endsWith("ai-agent-ingest/")
) {
ONEUPTIME_URL = URL.fromString(
ONEUPTIME_URL.addRoute("/ai-agent-ingest").toString(),
);
}
export const AI_AGENT_ID: ObjectID | null = process.env["AI_AGENT_ID"]
? new ObjectID(process.env["AI_AGENT_ID"])
: null;
if (!process.env["AI_AGENT_KEY"]) {
logger.error("AI_AGENT_KEY is not set");
process.exit();
}
export const AI_AGENT_KEY: string = process.env["AI_AGENT_KEY"];
export const HOSTNAME: string = process.env["HOSTNAME"] || "localhost";
export const PORT: Port = new Port(
process.env["PORT"] ? parseInt(process.env["PORT"]) : 3875,
);

58
AIAgent/Index.ts Normal file
View file

@ -0,0 +1,58 @@
import { PORT } from "./Config";
import AliveJob from "./Jobs/Alive";
import Register from "./Services/Register";
import { PromiseVoidFunction } from "Common/Types/FunctionTypes";
import logger from "Common/Server/Utils/Logger";
import App from "Common/Server/Utils/StartServer";
import Telemetry from "Common/Server/Utils/Telemetry";
import "ejs";
const APP_NAME: string = "ai-agent";
const init: PromiseVoidFunction = async (): Promise<void> => {
try {
// Initialize telemetry
Telemetry.init({
serviceName: APP_NAME,
});
logger.info("AI Agent Service - Starting...");
// init the app
await App.init({
appName: APP_NAME,
port: PORT,
isFrontendApp: false,
statusOptions: {
liveCheck: async () => {},
readyCheck: async () => {},
},
});
// add default routes
await App.addDefaultRoutes();
try {
// Register this AI Agent.
await Register.registerAIAgent();
logger.debug("AI Agent registered");
AliveJob();
} catch (err) {
logger.error("Register AI Agent failed");
logger.error(err);
throw err;
}
} catch (err) {
logger.error("App Init Failed:");
logger.error(err);
throw err;
}
};
init().catch((err: Error) => {
logger.error(err);
logger.error("Exiting node process");
process.exit(1);
});

56
AIAgent/Jobs/Alive.ts Normal file
View file

@ -0,0 +1,56 @@
import { ONEUPTIME_URL } from "../Config";
import Register from "../Services/Register";
import AIAgentAPIRequest from "../Utils/AIAgentAPIRequest";
import URL from "Common/Types/API/URL";
import API from "Common/Utils/API";
import { EVERY_MINUTE } from "Common/Utils/CronTime";
import LocalCache from "Common/Server/Infrastructure/LocalCache";
import BasicCron from "Common/Server/Utils/BasicCron";
import logger from "Common/Server/Utils/Logger";
import HTTPResponse from "Common/Types/API/HTTPResponse";
import { JSONObject } from "Common/Types/JSON";
const InitJob: VoidFunction = (): void => {
BasicCron({
jobName: "AIAgent:Alive",
options: {
schedule: EVERY_MINUTE,
runOnStartup: false,
},
runFunction: async () => {
logger.debug("Checking if AI Agent is alive...");
const aiAgentId: string | undefined = LocalCache.getString(
"AI_AGENT",
"AI_AGENT_ID",
);
if (!aiAgentId) {
logger.warn(
"AI Agent is not registered yet. Skipping alive check. Trying to register AI Agent again...",
);
await Register.registerAIAgent();
return;
}
logger.debug("AI Agent ID: " + aiAgentId.toString());
const aliveUrl: URL = URL.fromString(
ONEUPTIME_URL.toString(),
).addRoute("/alive");
const result: HTTPResponse<JSONObject> = await API.post({
url: aliveUrl,
data: AIAgentAPIRequest.getDefaultRequestBody(),
});
if (result.isSuccess()) {
logger.debug("AI Agent update sent to server successfully.");
} else {
logger.error("Failed to send AI Agent update to server.");
}
},
});
};
export default InitJob;

View file

@ -0,0 +1,75 @@
import { ONEUPTIME_URL, AI_AGENT_ID, AI_AGENT_KEY } from "../Config";
import AIAgentAPIRequest from "../Utils/AIAgentAPIRequest";
import HTTPResponse from "Common/Types/API/HTTPResponse";
import URL from "Common/Types/API/URL";
import { JSONObject } from "Common/Types/JSON";
import Sleep from "Common/Types/Sleep";
import API from "Common/Utils/API";
import LocalCache from "Common/Server/Infrastructure/LocalCache";
import logger from "Common/Server/Utils/Logger";
export default class Register {
public static async registerAIAgent(): Promise<void> {
// register AI agent with 10 retries and 30 second interval between each retry.
let currentRetry: number = 0;
const maxRetry: number = 10;
const retryIntervalInSeconds: number = 30;
while (currentRetry < maxRetry) {
try {
logger.debug(`Registering AI Agent. Attempt: ${currentRetry + 1}`);
await Register._registerAIAgent();
logger.debug(`AI Agent registered successfully.`);
break;
} catch (error) {
logger.error(
`Failed to register AI Agent. Retrying after ${retryIntervalInSeconds} seconds...`,
);
logger.error(error);
currentRetry++;
await Sleep.sleep(retryIntervalInSeconds * 1000);
}
}
}
private static async _registerAIAgent(): Promise<void> {
// Validate AI agent by sending alive request
if (!AI_AGENT_ID) {
logger.error("AI_AGENT_ID should be set");
return process.exit();
}
const aliveUrl: URL = URL.fromString(
ONEUPTIME_URL.toString(),
).addRoute("/alive");
logger.debug("Registering AI Agent...");
logger.debug("Sending request to: " + aliveUrl.toString());
const result: HTTPResponse<JSONObject> = await API.post({
url: aliveUrl,
data: {
aiAgentKey: AI_AGENT_KEY.toString(),
aiAgentId: AI_AGENT_ID.toString(),
},
});
if (result.isSuccess()) {
LocalCache.setString(
"AI_AGENT",
"AI_AGENT_ID",
AI_AGENT_ID.toString() as string,
);
logger.debug("AI Agent registered successfully");
} else {
throw new Error("Failed to register AI Agent: " + result.statusCode);
}
logger.debug(
`AI Agent ID: ${LocalCache.getString("AI_AGENT", "AI_AGENT_ID") || "Unknown"}`,
);
}
}

17
AIAgent/Utils/AIAgent.ts Normal file
View file

@ -0,0 +1,17 @@
import BadDataException from "Common/Types/Exception/BadDataException";
import ObjectID from "Common/Types/ObjectID";
import LocalCache from "Common/Server/Infrastructure/LocalCache";
export default class AIAgentUtil {
public static getAIAgentId(): ObjectID {
const id: string | undefined =
LocalCache.getString("AI_AGENT", "AI_AGENT_ID") ||
process.env["AI_AGENT_ID"];
if (!id) {
throw new BadDataException("AI Agent ID not found");
}
return new ObjectID(id);
}
}

View file

@ -0,0 +1,12 @@
import { AI_AGENT_KEY } from "../Config";
import AIAgentUtil from "./AIAgent";
import { JSONObject } from "Common/Types/JSON";
export default class AIAgentAPIRequest {
public static getDefaultRequestBody(): JSONObject {
return {
aiAgentKey: AI_AGENT_KEY,
aiAgentId: AIAgentUtil.getAIAgentId().toString(),
};
}
}

11
AIAgent/nodemon.json Normal file
View file

@ -0,0 +1,11 @@
{
"watch": [
"./",
"../Common"
],
"ext": "ts,tsx",
"ignore": ["./node_modules/**", "./public/**", "./bin/**", "./build/**"],
"watchOptions": {"useFsEvents": false, "interval": 500},
"env": {"TS_NODE_TRANSPILE_ONLY": "1", "TS_NODE_FILES": "false"},
"exec": "node -r ts-node/register/transpile-only Index.ts"
}

36
AIAgent/package.json Normal file
View file

@ -0,0 +1,36 @@
{
"name": "@oneuptime/ai-agent",
"version": "1.0.0",
"description": "OneUptime AI Agent",
"repository": {
"type": "git",
"url": "https://github.com/OneUptime/oneuptime"
},
"main": "index.js",
"scripts": {
"start": "export NODE_OPTIONS='--max-old-space-size=8096' && node --require ts-node/register Index.ts",
"compile": "tsc",
"clear-modules": "rm -rf node_modules && rm package-lock.json && npm install",
"dev": "npx nodemon",
"audit": "npm audit --audit-level=low",
"dep-check": "npm install -g depcheck && depcheck ./ --skip-missing=true",
"test": "jest --detectOpenHandles --passWithNoTests",
"coverage": "jest --detectOpenHandles --coverage",
"debug:test": "node --inspect node_modules/.bin/jest --runInBand ./Tests --detectOpenHandles"
},
"author": "OneUptime <hello@oneuptime.com> (https://oneuptime.com/)",
"license": "Apache-2.0",
"dependencies": {
"axios": "^1.13.1",
"Common": "file:../Common",
"ejs": "^3.1.10",
"ts-node": "^10.9.1"
},
"devDependencies": {
"@types/jest": "^27.5.2",
"@types/node": "^17.0.31",
"jest": "^28.1.0",
"nodemon": "^2.0.20",
"ts-jest": "^28.0.2"
}
}

45
AIAgent/tsconfig.json Normal file
View file

@ -0,0 +1,45 @@
{
"ts-node": {
"compilerOptions": {
"module": "commonjs",
"resolveJsonModule": true
}
},
"compilerOptions": {
"target": "es2017",
"jsx": "react",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"rootDir": "",
"moduleResolution": "node",
"typeRoots": [
"./node_modules/@types"
],
"types": ["node", "jest"],
"sourceMap": true,
"outDir": "build/dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"useUnknownInCatchVariables": true,
"alwaysStrict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"skipLibCheck": true,
"resolveJsonModule": true
},
"include": ["/**/*.ts"],
"exclude": ["node_modules"]
}

View file

@ -0,0 +1,82 @@
import BadDataException from "Common/Types/Exception/BadDataException";
import { JSONObject } from "Common/Types/JSON";
import ObjectID from "Common/Types/ObjectID";
import AIAgentService from "Common/Server/Services/AIAgentService";
import Express, {
ExpressRequest,
ExpressResponse,
ExpressRouter,
NextFunction,
} from "Common/Server/Utils/Express";
import Response from "Common/Server/Utils/Response";
import AIAgent from "Common/Models/DatabaseModels/AIAgent";
const router: ExpressRouter = Express.getRouter();
// Middleware to authorize AI Agent requests
async function isAuthorizedAIAgentMiddleware(
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction,
): Promise<void> {
const data: JSONObject = req.body;
if (!data["aiAgentId"] || !data["aiAgentKey"]) {
return Response.sendErrorResponse(
req,
res,
new BadDataException("aiAgentId or aiAgentKey is missing"),
);
}
const aiAgentId: ObjectID = new ObjectID(data["aiAgentId"] as string);
const aiAgentKey: string = data["aiAgentKey"] as string;
const aiAgent: AIAgent | null = await AIAgentService.findOneBy({
query: {
_id: aiAgentId.toString(),
secretKey: aiAgentKey,
},
select: {
_id: true,
},
props: {
isRoot: true,
},
});
if (!aiAgent) {
return Response.sendErrorResponse(
req,
res,
new BadDataException("Invalid AI Agent ID or AI Agent Key"),
);
}
// Update last alive
await AIAgentService.updateLastAlive(aiAgentId);
return next();
}
router.post(
"/alive",
isAuthorizedAIAgentMiddleware,
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction,
): Promise<void> => {
try {
// Update last alive in AI Agent and return success response.
// The middleware already updates lastAlive, so we just return success.
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
return next(err);
}
},
);
export default router;

View file

@ -0,0 +1,16 @@
import AIAgentIngestAPI from "./API/AIAgentIngest";
import FeatureSet from "Common/Server/Types/FeatureSet";
import Express, { ExpressApplication } from "Common/Server/Utils/Express";
const AIAgentIngestFeatureSet: FeatureSet = {
init: async (): Promise<void> => {
const app: ExpressApplication = Express.getExpressApp();
const APP_NAME: string = "ai-agent-ingest";
// Mount the AI Agent ingest API routes
app.use([`/${APP_NAME}`, "/"], AIAgentIngestAPI);
},
};
export default AIAgentIngestFeatureSet;

View file

@ -2,6 +2,7 @@ import BaseAPIRoutes from "./FeatureSet/BaseAPI/Index";
// import FeatureSets.
import IdentityRoutes from "./FeatureSet/Identity/Index";
import NotificationRoutes from "./FeatureSet/Notification/Index";
import AIAgentIngestRoutes from "./FeatureSet/AIAgentIngest/Index";
import { PromiseVoidFunction } from "Common/Types/FunctionTypes";
import { ClickhouseAppInstance } from "Common/Server/Infrastructure/ClickhouseDatabase";
import PostgresAppInstance from "Common/Server/Infrastructure/PostgresDatabase";
@ -94,6 +95,7 @@ const init: PromiseVoidFunction = async (): Promise<void> => {
await IdentityRoutes.init();
await NotificationRoutes.init();
await BaseAPIRoutes.init();
await AIAgentIngestRoutes.init();
// Add default routes to the app
await App.addDefaultRoutes();

View file

@ -0,0 +1,124 @@
{{- if .Values.aiAgent.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ printf "%s-%s" $.Release.Name "ai-agent" }}
namespace: {{ $.Release.Namespace }}
labels:
app: {{ printf "%s-%s" $.Release.Name "ai-agent" }}
app.kubernetes.io/part-of: oneuptime
app.kubernetes.io/managed-by: Helm
appname: oneuptime
{{- if $.Values.deployment.includeTimestampLabel }}
date: "{{ now | unixEpoch }}"
{{- end }}
spec:
selector:
matchLabels:
app: {{ printf "%s-%s" $.Release.Name "ai-agent" }}
{{- if and (ne $.Values.aiAgent.replicaCount nil) $.Values.aiAgent.disableAutoscaler }}
replicas: {{ $.Values.aiAgent.replicaCount }}
{{- else }}
{{- if or (not $.Values.autoscaling.enabled) ($.Values.aiAgent.disableAutoscaler) }}
replicas: {{ $.Values.deployment.replicaCount }}
{{- end }}
{{- end }}
strategy: {{- toYaml $.Values.deployment.updateStrategy | nindent 4 }}
template:
metadata:
labels:
app: {{ printf "%s-%s" $.Release.Name "ai-agent" }}
{{- if $.Values.deployment.includeTimestampLabel }}
date: "{{ now | unixEpoch }}"
{{- end }}
appname: oneuptime
spec:
{{- if $.Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml $.Values.imagePullSecrets | nindent 8 }}
{{- end }}
{{- if $.Values.aiAgent.podSecurityContext }}
securityContext:
{{- toYaml $.Values.aiAgent.podSecurityContext | nindent 8 }}
{{- else if $.Values.podSecurityContext }}
securityContext:
{{- toYaml $.Values.podSecurityContext | nindent 8 }}
{{- end }}
{{- if $.Values.affinity }}
affinity: {{- $.Values.affinity | toYaml | nindent 8 }}
{{- end }}
{{- if $.Values.tolerations }}
tolerations: {{- $.Values.tolerations | toYaml | nindent 8 }}
{{- end }}
{{- if $.Values.aiAgent.nodeSelector }}
nodeSelector:
{{- toYaml $.Values.aiAgent.nodeSelector | nindent 8 }}
{{- else if $.Values.nodeSelector }}
nodeSelector:
{{- toYaml $.Values.nodeSelector | nindent 8 }}
{{- end }}
containers:
- image: {{ include "oneuptime.image" (dict "Values" $.Values "ServiceName" "ai-agent") }}
name: {{ printf "%s-%s" $.Release.Name "ai-agent" }}
{{- if $.Values.aiAgent.containerSecurityContext }}
securityContext:
{{- toYaml $.Values.aiAgent.containerSecurityContext | nindent 12 }}
{{- else if $.Values.containerSecurityContext }}
securityContext:
{{- toYaml $.Values.containerSecurityContext | nindent 12 }}
{{- end }}
imagePullPolicy: {{ $.Values.image.pullPolicy }}
env:
- name: BILLING_ENABLED
value: {{ $.Values.billing.enabled | squote }}
- name: LOG_LEVEL
value: {{ $.Values.logLevel }}
- name: PORT
value: {{ $.Values.aiAgent.ports.http | squote }}
- name: OPENTELEMETRY_EXPORTER_OTLP_HEADERS
value: {{ $.Values.openTelemetryExporter.headers }}
- name: OPENTELEMETRY_EXPORTER_OTLP_ENDPOINT
value: {{ $.Values.openTelemetryExporter.endpoint }}
- name: ONEUPTIME_URL
value: http://{{ $.Release.Name }}-app.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }}:{{ $.Values.app.ports.http }}
- name: AI_AGENT_ID
value: {{ $.Values.aiAgent.id | squote }}
- name: AI_AGENT_KEY
{{- if $.Values.aiAgent.key }}
value: {{ $.Values.aiAgent.key }}
{{- else }}
valueFrom:
secretKeyRef:
name: {{ printf "%s-%s" $.Release.Name "secrets" }}
key: ai-agent-key
{{- end }}
{{- if $.Values.aiAgent.disableTelemetryCollection }}
- name: DISABLE_TELEMETRY
value: {{ $.Values.aiAgent.disableTelemetryCollection | quote }}
{{- end }}
{{- include "oneuptime.env.runtime" (dict "Values" $.Values "Release" $.Release) | nindent 12 }}
ports:
- containerPort: {{ $.Values.aiAgent.ports.http }}
protocol: TCP
name: http
{{- if $.Values.aiAgent.resources }}
resources:
{{- toYaml $.Values.aiAgent.resources | nindent 12 }}
{{- end }}
restartPolicy: {{ $.Values.image.restartPolicy }}
---
# OneUptime AI Agent Service
{{- $aiAgentPort := $.Values.aiAgent.ports.http }}
{{- $aiAgentPorts := dict "port" $aiAgentPort -}}
{{- $aiAgentServiceArgs := dict "ServiceName" "ai-agent" "Ports" $aiAgentPorts "Release" $.Release "Values" $.Values -}}
{{- include "oneuptime.service" $aiAgentServiceArgs }}
---
{{- if not $.Values.aiAgent.disableAutoscaler }}
# OneUptime AI Agent autoscaler
{{- $aiAgentAutoScalerArgs := dict "ServiceName" "ai-agent" "Release" $.Release "Values" $.Values -}}
{{- include "oneuptime.autoscaler" $aiAgentAutoScalerArgs }}
{{- end }}
{{- end }}

View file

@ -31,6 +31,14 @@ stringData:
{{- end }}
{{- end }}
{{- if and $.Values.aiAgent.enabled (not $.Values.aiAgent.key) }}
{{- if (index (lookup "v1" "Secret" $.Release.Namespace (printf "%s-secrets" $.Release.Name)).data "ai-agent-key") }}
ai-agent-key: {{ (index (lookup "v1" "Secret" $.Release.Namespace (printf "%s-secrets" $.Release.Name)).data "ai-agent-key" | b64dec) }}
{{- else }}
ai-agent-key: {{ randAlphaNum 32 | quote }}
{{- end }}
{{- end }}
{{ else }} # install operation
{{- if .Values.oneuptimeSecret }}
@ -48,6 +56,10 @@ stringData:
{{printf "probe-%s" $key}}: {{ randAlphaNum 32 | quote }}
{{- end }}
{{- if and $.Values.aiAgent.enabled (not $.Values.aiAgent.key) }}
ai-agent-key: {{ randAlphaNum 32 | quote }}
{{- end }}
{{ end }}
---

View file

@ -777,6 +777,25 @@ mcp:
podSecurityContext: {}
containerSecurityContext: {}
# AI Agent Configuration
# Deploy this to run an AI Agent within your Kubernetes cluster
# Note: This is disabled by default. To enable, set enabled to true and provide the AI Agent credentials
aiAgent:
enabled: false
replicaCount: 1
disableTelemetryCollection: false
disableAutoscaler: false
# AI Agent ID from OneUptime dashboard (required when enabled)
id:
# AI Agent Key from OneUptime dashboard (will be stored in secrets if not provided)
key:
ports:
http: 3875
resources:
nodeSelector: {}
podSecurityContext: {}
containerSecurityContext: {}
serverMonitorIngest:
enabled: true
replicaCount: 1

View file

@ -299,6 +299,14 @@ LLM_SERVER_HUGGINGFACE_TOKEN=
LLM_SERVER_HUGGINGFACE_MODEL_NAME=
# AI Agent Configuration
# Only set these if you want to run a self-hosted AI Agent
# You can get the AI_AGENT_ID and AI_AGENT_KEY from the OneUptime Dashboard -> Project Settings -> AI Agents
AI_AGENT_ID=
AI_AGENT_KEY=
AI_AGENT_ONEUPTIME_URL=http://localhost
AI_AGENT_PORT=3876
# By default telemetry is disabled for all services in docker compose. If you want to enable telemetry for a service, then set the env var to false.
DISABLE_TELEMETRY_FOR_ACCOUNTS=true
DISABLE_TELEMETRY_FOR_APP=true
@ -309,7 +317,7 @@ DISABLE_TELEMETRY_FOR_INCOMING_REQUEST_INGEST=true
DISABLE_TELEMETRY_FOR_TEST_SERVER=true
DISABLE_TELEMETRY_FOR_STATUS_PAGE=true
DISABLE_TELEMETRY_FOR_DASHBOARD=true
DISABLE_TELEMETRY_FOR_PROBE=true
DISABLE_TELEMETRY_FOR_PROBE=true
DISABLE_TELEMETRY_FOR_ADMIN_DASHBOARD=true
DISABLE_TELEMETRY_FOR_OTEL_COLLECTOR=true
DISABLE_TELEMETRY_FOR_ISOLATED_VM=true
@ -317,6 +325,7 @@ DISABLE_TELEMETRY_FOR_INGRESS=true
DISABLE_TELEMETRY_FOR_WORKER=true
DISABLE_TELEMETRY_FOR_SERVER_MONITOR_INGEST=true
DISABLE_TELEMETRY_FOR_MCP=true
DISABLE_TELEMETRY_FOR_AI_AGENT=true
# OPENTELEMETRY_COLLECTOR env vars

View file

@ -383,7 +383,7 @@ services:
options:
max-size: "1000m"
probe-2:
probe-2:
restart: always
network_mode: host
environment:
@ -402,7 +402,20 @@ services:
driver: "local"
options:
max-size: "1000m"
ai-agent:
restart: always
network_mode: host
environment:
AI_AGENT_ID: ${AI_AGENT_ID}
AI_AGENT_KEY: ${AI_AGENT_KEY}
ONEUPTIME_URL: ${AI_AGENT_ONEUPTIME_URL}
DISABLE_TELEMETRY: ${DISABLE_TELEMETRY_FOR_AI_AGENT}
PORT: ${AI_AGENT_PORT}
logging:
driver: "local"
options:
max-size: "1000m"
otel-collector:
networks:

View file

@ -282,7 +282,7 @@ services:
context: .
dockerfile: ./Probe/Dockerfile
probe-2:
probe-2:
volumes:
- ./Probe:/usr/src/app:cached
# Use node modules of the container and not host system.
@ -292,7 +292,7 @@ services:
- /usr/src/Common/node_modules/
extends:
file: ./docker-compose.base.yml
service: probe-2
@ -301,6 +301,25 @@ services:
context: .
dockerfile: ./Probe/Dockerfile
ai-agent:
volumes:
- ./AIAgent:/usr/src/app:cached
# Use node modules of the container and not host system.
# https://stackoverflow.com/questions/29181032/add-a-volume-to-docker-but-exclude-a-sub-folder
- /usr/src/app/node_modules/
- ./Common:/usr/src/Common:cached
- /usr/src/Common/node_modules/
extends:
file: ./docker-compose.base.yml
service: ai-agent
build:
network: host
context: .
dockerfile: ./AIAgent/Dockerfile
isolated-vm:
volumes:
- ./IsolatedVM:/usr/src/app:cached