miladyai 2.0.0-alpha.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.js +7 -0
- package/dist/actions/emote.js +64 -0
- package/dist/actions/restart.js +81 -0
- package/dist/actions/send-message.js +152 -0
- package/dist/agent-admin-routes.js +82 -0
- package/dist/agent-lifecycle-routes.js +79 -0
- package/dist/agent-transfer-routes.js +102 -0
- package/dist/api/agent-admin-routes.js +82 -0
- package/dist/api/agent-lifecycle-routes.js +79 -0
- package/dist/api/agent-transfer-routes.js +102 -0
- package/dist/api/apps-hyperscape-routes.js +58 -0
- package/dist/api/apps-routes.js +114 -0
- package/dist/api/auth-routes.js +56 -0
- package/dist/api/autonomy-routes.js +44 -0
- package/dist/api/bug-report-routes.js +111 -0
- package/dist/api/character-routes.js +195 -0
- package/dist/api/cloud-routes.js +330 -0
- package/dist/api/cloud-status-routes.js +155 -0
- package/dist/api/compat-utils.js +111 -0
- package/dist/api/database.js +735 -0
- package/dist/api/diagnostics-routes.js +205 -0
- package/dist/api/drop-service.js +134 -0
- package/dist/api/early-logs.js +86 -0
- package/dist/api/http-helpers.js +131 -0
- package/dist/api/knowledge-routes.js +534 -0
- package/dist/api/memory-bounds.js +71 -0
- package/dist/api/models-routes.js +28 -0
- package/dist/api/og-tracker.js +36 -0
- package/dist/api/permissions-routes.js +109 -0
- package/dist/api/plugin-validation.js +198 -0
- package/dist/api/provider-switch-config.js +41 -0
- package/dist/api/registry-routes.js +86 -0
- package/dist/api/registry-service.js +164 -0
- package/dist/api/sandbox-routes.js +1112 -0
- package/dist/api/server.js +7949 -0
- package/dist/api/subscription-routes.js +172 -0
- package/dist/api/terminal-run-limits.js +24 -0
- package/dist/api/training-routes.js +158 -0
- package/dist/api/trajectory-routes.js +300 -0
- package/dist/api/trigger-routes.js +246 -0
- package/dist/api/twitter-verify.js +134 -0
- package/dist/api/tx-service.js +108 -0
- package/dist/api/wallet-routes.js +266 -0
- package/dist/api/wallet.js +568 -0
- package/dist/api/whatsapp-routes.js +182 -0
- package/dist/api/zip-utils.js +109 -0
- package/dist/apps-hyperscape-routes.js +58 -0
- package/dist/apps-routes.js +114 -0
- package/dist/ascii.js +20 -0
- package/dist/auth/anthropic.js +44 -0
- package/dist/auth/apply-stealth.js +41 -0
- package/dist/auth/claude-code-stealth.js +78 -0
- package/dist/auth/credentials.js +156 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/openai-codex.js +66 -0
- package/dist/auth/types.js +9 -0
- package/dist/auth-routes.js +56 -0
- package/dist/autonomy-routes.js +44 -0
- package/dist/bug-report-routes.js +111 -0
- package/dist/build-info.json +6 -0
- package/dist/character-routes.js +195 -0
- package/dist/cli/argv.js +63 -0
- package/dist/cli/banner.js +34 -0
- package/dist/cli/cli-name.js +21 -0
- package/dist/cli/cli-utils.js +16 -0
- package/dist/cli/git-commit.js +78 -0
- package/dist/cli/parse-duration.js +15 -0
- package/dist/cli/plugins-cli.js +590 -0
- package/dist/cli/profile-utils.js +9 -0
- package/dist/cli/profile.js +95 -0
- package/dist/cli/program/build-program.js +17 -0
- package/dist/cli/program/command-registry.js +23 -0
- package/dist/cli/program/help.js +47 -0
- package/dist/cli/program/preaction.js +33 -0
- package/dist/cli/program/register.config.js +106 -0
- package/dist/cli/program/register.configure.js +20 -0
- package/dist/cli/program/register.dashboard.js +124 -0
- package/dist/cli/program/register.models.js +23 -0
- package/dist/cli/program/register.setup.js +36 -0
- package/dist/cli/program/register.start.js +22 -0
- package/dist/cli/program/register.subclis.js +70 -0
- package/dist/cli/program/register.tui.js +163 -0
- package/dist/cli/program/register.update.js +154 -0
- package/dist/cli/program.js +3 -0
- package/dist/cli/run-main.js +37 -0
- package/dist/cli/version.js +7 -0
- package/dist/cloud/validate-url.js +93 -0
- package/dist/cloud-routes.js +330 -0
- package/dist/cloud-status-routes.js +155 -0
- package/dist/compat-utils.js +111 -0
- package/dist/config/config.js +69 -0
- package/dist/config/env-vars.js +19 -0
- package/dist/config/includes.js +121 -0
- package/dist/config/object-utils.js +7 -0
- package/dist/config/paths.js +38 -0
- package/dist/config/plugin-auto-enable.js +231 -0
- package/dist/config/schema.js +864 -0
- package/dist/config/telegram-custom-commands.js +76 -0
- package/dist/config/zod-schema.agent-runtime.js +519 -0
- package/dist/config/zod-schema.core.js +538 -0
- package/dist/config/zod-schema.hooks.js +103 -0
- package/dist/config/zod-schema.js +488 -0
- package/dist/config/zod-schema.providers-core.js +785 -0
- package/dist/config/zod-schema.session.js +73 -0
- package/dist/core-plugins.js +37 -0
- package/dist/custom-actions.js +250 -0
- package/dist/database.js +735 -0
- package/dist/diagnostics/integration-observability.js +57 -0
- package/dist/diagnostics-routes.js +205 -0
- package/dist/drop-service.js +134 -0
- package/dist/early-logs.js +24 -0
- package/dist/eliza.js +2061 -0
- package/dist/emotes/catalog.js +271 -0
- package/dist/entry.js +40 -0
- package/dist/hooks/discovery.js +167 -0
- package/dist/hooks/eligibility.js +64 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/loader.js +147 -0
- package/dist/hooks/registry.js +55 -0
- package/dist/http-helpers.js +131 -0
- package/dist/index.js +49 -0
- package/dist/knowledge-routes.js +534 -0
- package/dist/memory-bounds.js +71 -0
- package/dist/milady-plugin.js +90 -0
- package/dist/models-routes.js +28 -0
- package/dist/onboarding-names.js +78 -0
- package/dist/onboarding-presets.js +922 -0
- package/dist/package.json +1 -0
- package/dist/permissions-routes.js +109 -0
- package/dist/plugin-validation.js +107 -0
- package/dist/plugins/whatsapp/actions.js +91 -0
- package/dist/plugins/whatsapp/index.js +16 -0
- package/dist/plugins/whatsapp/service.js +270 -0
- package/dist/provider-switch-config.js +41 -0
- package/dist/providers/admin-trust.js +46 -0
- package/dist/providers/autonomous-state.js +101 -0
- package/dist/providers/session-bridge.js +86 -0
- package/dist/providers/session-utils.js +36 -0
- package/dist/providers/simple-mode.js +50 -0
- package/dist/providers/ui-catalog.js +15 -0
- package/dist/providers/workspace-provider.js +93 -0
- package/dist/providers/workspace.js +348 -0
- package/dist/registry-routes.js +86 -0
- package/dist/registry-service.js +164 -0
- package/dist/restart.js +40 -0
- package/dist/runtime/core-plugins.js +37 -0
- package/dist/runtime/custom-actions.js +250 -0
- package/dist/runtime/eliza.js +2061 -0
- package/dist/runtime/embedding-manager-support.js +185 -0
- package/dist/runtime/embedding-manager.js +193 -0
- package/dist/runtime/embedding-presets.js +54 -0
- package/dist/runtime/embedding-state.js +8 -0
- package/dist/runtime/milady-plugin.js +90 -0
- package/dist/runtime/onboarding-names.js +78 -0
- package/dist/runtime/restart.js +40 -0
- package/dist/runtime/version.js +7 -0
- package/dist/sandbox-routes.js +1112 -0
- package/dist/security/audit-log.js +149 -0
- package/dist/security/network-policy.js +70 -0
- package/dist/server.js +7949 -0
- package/dist/services/agent-export.js +559 -0
- package/dist/services/app-manager.js +389 -0
- package/dist/services/browser-capture.js +86 -0
- package/dist/services/fallback-training-service.js +128 -0
- package/dist/services/mcp-marketplace.js +134 -0
- package/dist/services/plugin-installer.js +396 -0
- package/dist/services/plugin-manager-types.js +15 -0
- package/dist/services/registry-client-app-meta.js +144 -0
- package/dist/services/registry-client-endpoints.js +166 -0
- package/dist/services/registry-client-local.js +271 -0
- package/dist/services/registry-client-network.js +93 -0
- package/dist/services/registry-client-queries.js +70 -0
- package/dist/services/registry-client.js +157 -0
- package/dist/services/sandbox-engine.js +511 -0
- package/dist/services/sandbox-manager.js +297 -0
- package/dist/services/self-updater.js +175 -0
- package/dist/services/skill-catalog-client.js +119 -0
- package/dist/services/skill-marketplace.js +521 -0
- package/dist/services/stream-manager.js +236 -0
- package/dist/services/update-checker.js +121 -0
- package/dist/services/update-notifier.js +29 -0
- package/dist/services/version-compat.js +78 -0
- package/dist/services/whatsapp-pairing.js +196 -0
- package/dist/shared/ui-catalog-prompt.js +728 -0
- package/dist/subscription-routes.js +172 -0
- package/dist/terminal/links.js +19 -0
- package/dist/terminal/palette.js +14 -0
- package/dist/terminal/theme.js +25 -0
- package/dist/terminal-run-limits.js +24 -0
- package/dist/training-routes.js +158 -0
- package/dist/trajectory-routes.js +300 -0
- package/dist/trigger-routes.js +246 -0
- package/dist/triggers/action.js +218 -0
- package/dist/triggers/runtime.js +281 -0
- package/dist/triggers/scheduling.js +295 -0
- package/dist/triggers/types.js +5 -0
- package/dist/tui/components/assistant-message.js +76 -0
- package/dist/tui/components/chat-editor.js +34 -0
- package/dist/tui/components/embeddings-overlay.js +46 -0
- package/dist/tui/components/footer.js +60 -0
- package/dist/tui/components/index.js +15 -0
- package/dist/tui/components/modal-frame.js +45 -0
- package/dist/tui/components/modal-style.js +15 -0
- package/dist/tui/components/model-selector.js +70 -0
- package/dist/tui/components/pinned-chat-layout.js +46 -0
- package/dist/tui/components/plugins-endpoints-tab.js +196 -0
- package/dist/tui/components/plugins-installed-tab-view.js +69 -0
- package/dist/tui/components/plugins-installed-tab.js +319 -0
- package/dist/tui/components/plugins-overlay-catalog.js +81 -0
- package/dist/tui/components/plugins-overlay-data-api.js +21 -0
- package/dist/tui/components/plugins-overlay-data-shared.js +20 -0
- package/dist/tui/components/plugins-overlay-data.js +323 -0
- package/dist/tui/components/plugins-overlay.js +117 -0
- package/dist/tui/components/plugins-store-tab.js +148 -0
- package/dist/tui/components/settings-overlay.js +61 -0
- package/dist/tui/components/status-bar.js +64 -0
- package/dist/tui/components/tool-execution.js +68 -0
- package/dist/tui/components/user-message.js +22 -0
- package/dist/tui/eliza-tui-bridge.js +606 -0
- package/dist/tui/index.js +370 -0
- package/dist/tui/modal-presets.js +33 -0
- package/dist/tui/model-spec.js +46 -0
- package/dist/tui/sse-parser.js +78 -0
- package/dist/tui/theme.js +110 -0
- package/dist/tui/titlebar-spinner.js +62 -0
- package/dist/tui/tui-app.js +311 -0
- package/dist/tui/ws-client.js +215 -0
- package/dist/twitter-verify.js +134 -0
- package/dist/tx-service.js +108 -0
- package/dist/utils/exec-safety.js +17 -0
- package/dist/utils/globals.js +20 -0
- package/dist/utils/milady-root.js +61 -0
- package/dist/utils/number-parsing.js +37 -0
- package/dist/version-resolver.js +37 -0
- package/dist/version.js +7 -0
- package/dist/wallet-routes.js +266 -0
- package/dist/wallet.js +568 -0
- package/dist/whatsapp-routes.js +182 -0
- package/dist/zip-utils.js +109 -0
- package/milady.mjs +14 -0
- package/package.json +111 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { buildTriggerConfig, buildTriggerMetadata, normalizeTriggerDraft } from "./scheduling.js";
|
|
2
|
+
import { TRIGGER_TASK_NAME, TRIGGER_TASK_TAGS, getTriggerLimit, listTriggerTasks, readTriggerConfig, taskToTriggerSummary, triggersFeatureEnabled } from "./runtime.js";
|
|
3
|
+
import { parsePositiveInteger } from "../utils/number-parsing.js";
|
|
4
|
+
import { ModelType, stringToUuid } from "@elizaos/core";
|
|
5
|
+
import crypto from "node:crypto";
|
|
6
|
+
|
|
7
|
+
//#region src/triggers/action.ts
|
|
8
|
+
const CREATE_TRIGGER_TASK_ACTION = "CREATE_TRIGGER_TASK";
|
|
9
|
+
const CREATE_TRIGGER_KEYWORDS = [
|
|
10
|
+
"create trigger",
|
|
11
|
+
"create a trigger",
|
|
12
|
+
"create task",
|
|
13
|
+
"schedule trigger",
|
|
14
|
+
"schedule task",
|
|
15
|
+
"run every",
|
|
16
|
+
"run at",
|
|
17
|
+
"every hour",
|
|
18
|
+
"every day"
|
|
19
|
+
];
|
|
20
|
+
function normalizeText(value) {
|
|
21
|
+
return value.trim().replace(/\s+/g, " ");
|
|
22
|
+
}
|
|
23
|
+
function parseTag(xml, tag) {
|
|
24
|
+
const match = new RegExp(`<${tag}>([\\s\\S]*?)<\\/${tag}>`, "i").exec(xml);
|
|
25
|
+
if (!match?.[1]) return void 0;
|
|
26
|
+
const text = normalizeText(match[1]);
|
|
27
|
+
return text.length > 0 ? text : void 0;
|
|
28
|
+
}
|
|
29
|
+
function parseExtraction(xml) {
|
|
30
|
+
return {
|
|
31
|
+
triggerType: parseTag(xml, "triggerType"),
|
|
32
|
+
displayName: parseTag(xml, "displayName"),
|
|
33
|
+
instructions: parseTag(xml, "instructions"),
|
|
34
|
+
wakeMode: parseTag(xml, "wakeMode"),
|
|
35
|
+
intervalMs: parseTag(xml, "intervalMs"),
|
|
36
|
+
scheduledAtIso: parseTag(xml, "scheduledAtIso"),
|
|
37
|
+
cronExpression: parseTag(xml, "cronExpression"),
|
|
38
|
+
maxRuns: parseTag(xml, "maxRuns")
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function deriveTriggerType(extracted) {
|
|
42
|
+
const type = extracted.triggerType?.toLowerCase();
|
|
43
|
+
if (type === "interval" || type === "once" || type === "cron") return type;
|
|
44
|
+
if (extracted.cronExpression) return "cron";
|
|
45
|
+
if (extracted.scheduledAtIso) return "once";
|
|
46
|
+
return "interval";
|
|
47
|
+
}
|
|
48
|
+
function extractionPrompt(userText) {
|
|
49
|
+
return [
|
|
50
|
+
"Extract trigger details from this request.",
|
|
51
|
+
"Return only XML with these keys:",
|
|
52
|
+
"triggerType, displayName, instructions, wakeMode, intervalMs, scheduledAtIso, cronExpression, maxRuns",
|
|
53
|
+
"Valid triggerType values: interval, once, cron",
|
|
54
|
+
"Valid wakeMode values: inject_now, next_autonomy_cycle",
|
|
55
|
+
"",
|
|
56
|
+
`Request: ${userText}`
|
|
57
|
+
].join("\n");
|
|
58
|
+
}
|
|
59
|
+
function scheduleText(summary) {
|
|
60
|
+
if (!summary) return "scheduled";
|
|
61
|
+
if (summary.triggerType === "interval") return `every ${summary.intervalMs ?? 0} ms`;
|
|
62
|
+
if (summary.triggerType === "once") return `once at ${summary.scheduledAtIso ?? "unknown time"}`;
|
|
63
|
+
return `on cron ${summary.cronExpression ?? "* * * * *"}`;
|
|
64
|
+
}
|
|
65
|
+
const createTriggerTaskAction = {
|
|
66
|
+
name: CREATE_TRIGGER_TASK_ACTION,
|
|
67
|
+
similes: ["CREATE_TRIGGER", "SCHEDULE_TRIGGER"],
|
|
68
|
+
description: "Create an autonomous trigger task that executes interval, once, or cron schedules",
|
|
69
|
+
validate: async (runtime, message) => {
|
|
70
|
+
if (!runtime.enableAutonomy) return false;
|
|
71
|
+
if (!triggersFeatureEnabled(runtime)) return false;
|
|
72
|
+
const text = message.content.text?.toLowerCase() ?? "";
|
|
73
|
+
if (!text) return false;
|
|
74
|
+
return CREATE_TRIGGER_KEYWORDS.some((keyword) => text.includes(keyword));
|
|
75
|
+
},
|
|
76
|
+
handler: async (runtime, message, _state, _options, callback) => {
|
|
77
|
+
const text = normalizeText(message.content.text ?? "");
|
|
78
|
+
if (!text) return {
|
|
79
|
+
success: false,
|
|
80
|
+
text: "Cannot create a trigger from empty text."
|
|
81
|
+
};
|
|
82
|
+
if (!runtime.enableAutonomy) return {
|
|
83
|
+
success: false,
|
|
84
|
+
text: "Autonomy mode is disabled, so trigger creation is unavailable."
|
|
85
|
+
};
|
|
86
|
+
if (!triggersFeatureEnabled(runtime)) return {
|
|
87
|
+
success: false,
|
|
88
|
+
text: "Triggers are disabled by configuration."
|
|
89
|
+
};
|
|
90
|
+
try {
|
|
91
|
+
let extraction = {};
|
|
92
|
+
let extractionFailed = false;
|
|
93
|
+
try {
|
|
94
|
+
extraction = parseExtraction(await runtime.useModel(ModelType.TEXT_SMALL, {
|
|
95
|
+
prompt: extractionPrompt(text),
|
|
96
|
+
stopSequences: []
|
|
97
|
+
}));
|
|
98
|
+
} catch (extractionError) {
|
|
99
|
+
extractionFailed = true;
|
|
100
|
+
runtime.logger.warn({
|
|
101
|
+
src: "trigger-action",
|
|
102
|
+
error: extractionError instanceof Error ? extractionError.message : String(extractionError)
|
|
103
|
+
}, "LLM extraction failed, using fallback defaults from user text");
|
|
104
|
+
}
|
|
105
|
+
const creator = String(message.entityId ?? runtime.agentId);
|
|
106
|
+
const triggerType = deriveTriggerType(extraction);
|
|
107
|
+
const normalized = normalizeTriggerDraft({
|
|
108
|
+
input: {
|
|
109
|
+
displayName: extraction.displayName ?? `Trigger: ${text.slice(0, 64)}`,
|
|
110
|
+
instructions: extraction.instructions ?? text,
|
|
111
|
+
triggerType,
|
|
112
|
+
wakeMode: extraction.wakeMode === "next_autonomy_cycle" ? "next_autonomy_cycle" : "inject_now",
|
|
113
|
+
enabled: true,
|
|
114
|
+
createdBy: creator,
|
|
115
|
+
intervalMs: parsePositiveInteger(extraction.intervalMs),
|
|
116
|
+
scheduledAtIso: extraction.scheduledAtIso,
|
|
117
|
+
cronExpression: extraction.cronExpression,
|
|
118
|
+
maxRuns: parsePositiveInteger(extraction.maxRuns)
|
|
119
|
+
},
|
|
120
|
+
fallback: {
|
|
121
|
+
displayName: `Trigger: ${text.slice(0, 64)}`,
|
|
122
|
+
instructions: text,
|
|
123
|
+
triggerType: "interval",
|
|
124
|
+
wakeMode: "inject_now",
|
|
125
|
+
enabled: true,
|
|
126
|
+
createdBy: creator
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
if (!normalized.draft) return {
|
|
130
|
+
success: false,
|
|
131
|
+
text: normalized.error ?? "Invalid trigger request"
|
|
132
|
+
};
|
|
133
|
+
const existingTasks = await listTriggerTasks(runtime);
|
|
134
|
+
const limit = getTriggerLimit(runtime);
|
|
135
|
+
if (existingTasks.filter((task) => {
|
|
136
|
+
const trigger = readTriggerConfig(task);
|
|
137
|
+
return trigger?.enabled && trigger.createdBy === creator;
|
|
138
|
+
}).length >= limit) return {
|
|
139
|
+
success: false,
|
|
140
|
+
text: `Trigger limit reached (${limit} active triggers).`
|
|
141
|
+
};
|
|
142
|
+
const triggerId = stringToUuid(crypto.randomUUID());
|
|
143
|
+
const triggerConfig = buildTriggerConfig({
|
|
144
|
+
draft: normalized.draft,
|
|
145
|
+
triggerId
|
|
146
|
+
});
|
|
147
|
+
const duplicate = existingTasks.find((task) => {
|
|
148
|
+
const existingTrigger = readTriggerConfig(task);
|
|
149
|
+
if (!existingTrigger?.enabled) return false;
|
|
150
|
+
if (existingTrigger.dedupeKey && triggerConfig.dedupeKey) return existingTrigger.dedupeKey === triggerConfig.dedupeKey;
|
|
151
|
+
return normalizeText(existingTrigger.instructions).toLowerCase() === normalizeText(triggerConfig.instructions).toLowerCase() && existingTrigger.triggerType === triggerConfig.triggerType && (existingTrigger.intervalMs ?? 0) === (triggerConfig.intervalMs ?? 0) && (existingTrigger.scheduledAtIso ?? "") === (triggerConfig.scheduledAtIso ?? "") && (existingTrigger.cronExpression ?? "") === (triggerConfig.cronExpression ?? "");
|
|
152
|
+
});
|
|
153
|
+
if (duplicate?.id) {
|
|
154
|
+
const duplicateText = `Equivalent trigger already exists (${taskToTriggerSummary(duplicate)?.displayName ?? duplicate.id}).`;
|
|
155
|
+
if (callback) await callback({
|
|
156
|
+
text: duplicateText,
|
|
157
|
+
action: CREATE_TRIGGER_TASK_ACTION,
|
|
158
|
+
metadata: { duplicateTaskId: duplicate.id }
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
success: true,
|
|
162
|
+
text: duplicateText,
|
|
163
|
+
data: { duplicateTaskId: duplicate.id }
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const metadata = buildTriggerMetadata({
|
|
167
|
+
trigger: triggerConfig,
|
|
168
|
+
nowMs: Date.now()
|
|
169
|
+
});
|
|
170
|
+
if (!metadata) return {
|
|
171
|
+
success: false,
|
|
172
|
+
text: "Unable to compute trigger schedule."
|
|
173
|
+
};
|
|
174
|
+
const roomId = runtime.getService("AUTONOMY")?.getAutonomousRoomId?.() ?? message.roomId;
|
|
175
|
+
const createdTaskId = await runtime.createTask({
|
|
176
|
+
name: TRIGGER_TASK_NAME,
|
|
177
|
+
description: triggerConfig.displayName,
|
|
178
|
+
roomId,
|
|
179
|
+
tags: [...TRIGGER_TASK_TAGS],
|
|
180
|
+
metadata
|
|
181
|
+
});
|
|
182
|
+
const createdTask = await runtime.getTask(createdTaskId);
|
|
183
|
+
const createdSummary = createdTask ? taskToTriggerSummary(createdTask) : null;
|
|
184
|
+
const fallbackNote = extractionFailed ? " (Note: AI extraction failed; trigger was created from your raw text with default settings.)" : "";
|
|
185
|
+
const successText = `Created trigger "${triggerConfig.displayName}" ${scheduleText(createdSummary)}.${fallbackNote}`;
|
|
186
|
+
if (callback) await callback({
|
|
187
|
+
text: successText,
|
|
188
|
+
action: CREATE_TRIGGER_TASK_ACTION,
|
|
189
|
+
metadata: {
|
|
190
|
+
triggerId,
|
|
191
|
+
taskId: String(createdTaskId),
|
|
192
|
+
triggerType: triggerConfig.triggerType
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
success: true,
|
|
197
|
+
text: successText,
|
|
198
|
+
values: {
|
|
199
|
+
triggerId,
|
|
200
|
+
taskId: String(createdTaskId)
|
|
201
|
+
},
|
|
202
|
+
data: {
|
|
203
|
+
triggerId,
|
|
204
|
+
taskId: String(createdTaskId),
|
|
205
|
+
triggerType: triggerConfig.triggerType
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
} catch (error) {
|
|
209
|
+
return {
|
|
210
|
+
success: false,
|
|
211
|
+
text: error instanceof Error ? error.message : "Failed to create trigger"
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
//#endregion
|
|
218
|
+
export { createTriggerTaskAction };
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { DISABLED_TRIGGER_INTERVAL_MS, MAX_TRIGGER_RUN_HISTORY, buildTriggerMetadata } from "./scheduling.js";
|
|
2
|
+
import { stringToUuid } from "@elizaos/core";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
|
|
5
|
+
//#region src/triggers/runtime.ts
|
|
6
|
+
const TRIGGER_TASK_NAME = "TRIGGER_DISPATCH";
|
|
7
|
+
const TRIGGER_TASK_TAGS = [
|
|
8
|
+
"queue",
|
|
9
|
+
"repeat",
|
|
10
|
+
"trigger"
|
|
11
|
+
];
|
|
12
|
+
const DEFAULT_MAX_ACTIVE_TRIGGERS = 100;
|
|
13
|
+
/**
|
|
14
|
+
* In-memory trigger execution metrics per agent.
|
|
15
|
+
* These counters are approximations for the /api/triggers/health endpoint
|
|
16
|
+
* and reset on process restart. Durable execution history is stored in
|
|
17
|
+
* task.metadata.triggerRuns (persisted to database via the task system).
|
|
18
|
+
*/
|
|
19
|
+
const metricsByAgent = /* @__PURE__ */ new Map();
|
|
20
|
+
function getMetrics(agentId) {
|
|
21
|
+
const current = metricsByAgent.get(agentId);
|
|
22
|
+
if (current) return current;
|
|
23
|
+
const created = {
|
|
24
|
+
totalExecutions: 0,
|
|
25
|
+
totalFailures: 0,
|
|
26
|
+
totalSkipped: 0
|
|
27
|
+
};
|
|
28
|
+
metricsByAgent.set(agentId, created);
|
|
29
|
+
return created;
|
|
30
|
+
}
|
|
31
|
+
function recordExecutionMetric(agentId, status, ts) {
|
|
32
|
+
const metrics = getMetrics(agentId);
|
|
33
|
+
if (status === "success" || status === "error") {
|
|
34
|
+
metrics.totalExecutions += 1;
|
|
35
|
+
metrics.lastExecutionAt = ts;
|
|
36
|
+
}
|
|
37
|
+
if (status === "error") metrics.totalFailures += 1;
|
|
38
|
+
if (status === "skipped") metrics.totalSkipped += 1;
|
|
39
|
+
}
|
|
40
|
+
function appendRunRecord(existing, record) {
|
|
41
|
+
const runs = [...existing ?? [], record];
|
|
42
|
+
return runs.length <= MAX_TRIGGER_RUN_HISTORY ? runs : runs.slice(runs.length - MAX_TRIGGER_RUN_HISTORY);
|
|
43
|
+
}
|
|
44
|
+
function taskMetadata(task) {
|
|
45
|
+
return task.metadata ?? {};
|
|
46
|
+
}
|
|
47
|
+
function readTriggerConfig(task) {
|
|
48
|
+
const trigger = taskMetadata(task).trigger;
|
|
49
|
+
if (!trigger || typeof trigger !== "object" || Array.isArray(trigger)) return null;
|
|
50
|
+
return trigger.triggerId ? trigger : null;
|
|
51
|
+
}
|
|
52
|
+
function readTriggerRuns(task) {
|
|
53
|
+
const runs = taskMetadata(task).triggerRuns;
|
|
54
|
+
return Array.isArray(runs) ? runs : [];
|
|
55
|
+
}
|
|
56
|
+
function triggersFeatureEnabled(runtime) {
|
|
57
|
+
const runtimeSetting = runtime?.getSetting("MILADY_TRIGGERS_ENABLED");
|
|
58
|
+
if (runtimeSetting === false || runtimeSetting === "false" || runtimeSetting === "0") return false;
|
|
59
|
+
const env = process.env.MILADY_TRIGGERS_ENABLED;
|
|
60
|
+
if (!env) return true;
|
|
61
|
+
const normalized = env.trim().toLowerCase();
|
|
62
|
+
return normalized !== "0" && normalized !== "false";
|
|
63
|
+
}
|
|
64
|
+
function getTriggerLimit(runtime) {
|
|
65
|
+
const runtimeSetting = runtime?.getSetting("MILADY_TRIGGERS_MAX_ACTIVE");
|
|
66
|
+
if (typeof runtimeSetting === "number" && Number.isFinite(runtimeSetting)) return Math.max(1, Math.floor(runtimeSetting));
|
|
67
|
+
if (typeof runtimeSetting === "string" && /^\d+$/.test(runtimeSetting)) return Math.max(1, Number(runtimeSetting));
|
|
68
|
+
const env = process.env.MILADY_TRIGGERS_MAX_ACTIVE;
|
|
69
|
+
if (env && /^\d+$/.test(env)) return Math.max(1, Number(env));
|
|
70
|
+
return DEFAULT_MAX_ACTIVE_TRIGGERS;
|
|
71
|
+
}
|
|
72
|
+
async function dispatchInstruction(runtime, taskId, trigger) {
|
|
73
|
+
const autonomyService = runtime.getService("autonomy") ?? runtime.getService("AUTONOMY");
|
|
74
|
+
if (!autonomyService?.injectAutonomousInstruction) {
|
|
75
|
+
runtime.logger.warn?.(`Autonomy service missing injectAutonomousInstruction (taskId=${taskId}, triggerId=${trigger.triggerId})`);
|
|
76
|
+
throw new Error("Autonomy service unavailable for trigger dispatch");
|
|
77
|
+
}
|
|
78
|
+
const roomId = typeof autonomyService.getAutonomousRoomId === "function" ? autonomyService.getAutonomousRoomId() : void 0;
|
|
79
|
+
await autonomyService.injectAutonomousInstruction({
|
|
80
|
+
instructions: trigger.instructions,
|
|
81
|
+
source: "trigger-runtime",
|
|
82
|
+
wakeMode: trigger.wakeMode,
|
|
83
|
+
triggerId: trigger.triggerId,
|
|
84
|
+
triggerTaskId: taskId,
|
|
85
|
+
taskId,
|
|
86
|
+
roomId
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async function executeTriggerTask(runtime, task, options) {
|
|
90
|
+
if (!task.id) return {
|
|
91
|
+
status: "skipped",
|
|
92
|
+
taskDeleted: false
|
|
93
|
+
};
|
|
94
|
+
const trigger = readTriggerConfig(task);
|
|
95
|
+
if (!trigger) {
|
|
96
|
+
recordExecutionMetric(runtime.agentId, "skipped", Date.now());
|
|
97
|
+
return {
|
|
98
|
+
status: "skipped",
|
|
99
|
+
taskDeleted: false
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (!trigger.enabled && !options.force) {
|
|
103
|
+
recordExecutionMetric(runtime.agentId, "skipped", Date.now());
|
|
104
|
+
return {
|
|
105
|
+
status: "skipped",
|
|
106
|
+
taskDeleted: false
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (typeof trigger.maxRuns === "number" && trigger.maxRuns > 0 && trigger.runCount >= trigger.maxRuns) {
|
|
110
|
+
await runtime.deleteTask(task.id);
|
|
111
|
+
recordExecutionMetric(runtime.agentId, "skipped", Date.now());
|
|
112
|
+
return {
|
|
113
|
+
status: "skipped",
|
|
114
|
+
taskDeleted: true
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const startedAt = Date.now();
|
|
118
|
+
let status = "success";
|
|
119
|
+
let errorMessage = "";
|
|
120
|
+
try {
|
|
121
|
+
await dispatchInstruction(runtime, task.id, trigger);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
status = "error";
|
|
124
|
+
errorMessage = error instanceof Error ? error.message : String(error);
|
|
125
|
+
runtime.logger.error({
|
|
126
|
+
src: "trigger-runtime",
|
|
127
|
+
agentId: runtime.agentId,
|
|
128
|
+
taskId: task.id,
|
|
129
|
+
triggerId: trigger.triggerId,
|
|
130
|
+
error: errorMessage
|
|
131
|
+
}, "Trigger execution failed");
|
|
132
|
+
}
|
|
133
|
+
if (status === "success") runtime.logger.info({
|
|
134
|
+
src: "trigger-runtime",
|
|
135
|
+
triggerId: trigger.triggerId,
|
|
136
|
+
triggerName: trigger.displayName,
|
|
137
|
+
triggerType: trigger.triggerType,
|
|
138
|
+
source: options.source,
|
|
139
|
+
latencyMs: Date.now() - startedAt
|
|
140
|
+
}, `Trigger "${trigger.displayName}" executed successfully`);
|
|
141
|
+
const finishedAt = Date.now();
|
|
142
|
+
const runRecord = {
|
|
143
|
+
triggerRunId: stringToUuid(crypto.randomUUID()),
|
|
144
|
+
triggerId: trigger.triggerId,
|
|
145
|
+
taskId: task.id,
|
|
146
|
+
startedAt,
|
|
147
|
+
finishedAt,
|
|
148
|
+
status,
|
|
149
|
+
error: errorMessage || void 0,
|
|
150
|
+
latencyMs: finishedAt - startedAt,
|
|
151
|
+
source: options.source
|
|
152
|
+
};
|
|
153
|
+
const updatedTrigger = {
|
|
154
|
+
...trigger,
|
|
155
|
+
runCount: trigger.runCount + 1,
|
|
156
|
+
lastRunAtIso: new Date(finishedAt).toISOString(),
|
|
157
|
+
lastStatus: status,
|
|
158
|
+
lastError: errorMessage || void 0
|
|
159
|
+
};
|
|
160
|
+
if (updatedTrigger.triggerType === "once" || typeof updatedTrigger.maxRuns === "number" && updatedTrigger.maxRuns > 0 && updatedTrigger.runCount >= updatedTrigger.maxRuns) {
|
|
161
|
+
await runtime.deleteTask(task.id);
|
|
162
|
+
recordExecutionMetric(runtime.agentId, status, finishedAt);
|
|
163
|
+
return {
|
|
164
|
+
status,
|
|
165
|
+
error: errorMessage || void 0,
|
|
166
|
+
runRecord,
|
|
167
|
+
taskDeleted: true
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const existingMetadata = taskMetadata(task);
|
|
171
|
+
const nextMetadata = buildTriggerMetadata({
|
|
172
|
+
existingMetadata,
|
|
173
|
+
trigger: updatedTrigger,
|
|
174
|
+
nowMs: finishedAt
|
|
175
|
+
});
|
|
176
|
+
let metadataToPersist;
|
|
177
|
+
if (!nextMetadata) metadataToPersist = {
|
|
178
|
+
...existingMetadata,
|
|
179
|
+
updatedAt: finishedAt,
|
|
180
|
+
updateInterval: DISABLED_TRIGGER_INTERVAL_MS,
|
|
181
|
+
trigger: {
|
|
182
|
+
...updatedTrigger,
|
|
183
|
+
enabled: false,
|
|
184
|
+
nextRunAtMs: finishedAt + DISABLED_TRIGGER_INTERVAL_MS,
|
|
185
|
+
lastError: updatedTrigger.lastError ?? "Failed to compute next trigger schedule"
|
|
186
|
+
},
|
|
187
|
+
triggerRuns: appendRunRecord(existingMetadata.triggerRuns, runRecord)
|
|
188
|
+
};
|
|
189
|
+
else metadataToPersist = {
|
|
190
|
+
...nextMetadata,
|
|
191
|
+
triggerRuns: appendRunRecord(existingMetadata.triggerRuns, runRecord)
|
|
192
|
+
};
|
|
193
|
+
await runtime.updateTask(task.id, {
|
|
194
|
+
description: metadataToPersist.trigger?.displayName ?? task.description,
|
|
195
|
+
metadata: metadataToPersist
|
|
196
|
+
});
|
|
197
|
+
recordExecutionMetric(runtime.agentId, status, finishedAt);
|
|
198
|
+
return {
|
|
199
|
+
status,
|
|
200
|
+
error: errorMessage || void 0,
|
|
201
|
+
runRecord,
|
|
202
|
+
taskDeleted: false
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function registerTriggerTaskWorker(runtime) {
|
|
206
|
+
if (runtime.getTaskWorker(TRIGGER_TASK_NAME)) return;
|
|
207
|
+
runtime.registerTaskWorker({
|
|
208
|
+
name: TRIGGER_TASK_NAME,
|
|
209
|
+
validate: async () => true,
|
|
210
|
+
execute: async (rt, options, task) => {
|
|
211
|
+
await executeTriggerTask(rt, task, {
|
|
212
|
+
source: options.source === "manual" ? "manual" : "scheduler",
|
|
213
|
+
force: options.force === true
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
async function listTriggerTasks(runtime) {
|
|
219
|
+
if (!triggersFeatureEnabled(runtime)) return [];
|
|
220
|
+
return runtime.getTasks({ tags: [...TRIGGER_TASK_TAGS] });
|
|
221
|
+
}
|
|
222
|
+
function taskToTriggerSummary(task) {
|
|
223
|
+
const trigger = readTriggerConfig(task);
|
|
224
|
+
if (!trigger || !task.id) return null;
|
|
225
|
+
const metadata = taskMetadata(task);
|
|
226
|
+
return {
|
|
227
|
+
id: trigger.triggerId,
|
|
228
|
+
taskId: task.id,
|
|
229
|
+
displayName: trigger.displayName,
|
|
230
|
+
instructions: trigger.instructions,
|
|
231
|
+
triggerType: trigger.triggerType,
|
|
232
|
+
enabled: trigger.enabled,
|
|
233
|
+
wakeMode: trigger.wakeMode,
|
|
234
|
+
createdBy: trigger.createdBy,
|
|
235
|
+
timezone: trigger.timezone,
|
|
236
|
+
intervalMs: trigger.intervalMs,
|
|
237
|
+
scheduledAtIso: trigger.scheduledAtIso,
|
|
238
|
+
cronExpression: trigger.cronExpression,
|
|
239
|
+
maxRuns: trigger.maxRuns,
|
|
240
|
+
runCount: trigger.runCount,
|
|
241
|
+
nextRunAtMs: trigger.nextRunAtMs,
|
|
242
|
+
lastRunAtIso: trigger.lastRunAtIso,
|
|
243
|
+
lastStatus: trigger.lastStatus,
|
|
244
|
+
lastError: trigger.lastError,
|
|
245
|
+
updatedAt: metadata.updatedAt,
|
|
246
|
+
updateInterval: metadata.updateInterval
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
async function getTriggerHealthSnapshot(runtime) {
|
|
250
|
+
const tasks = await listTriggerTasks(runtime);
|
|
251
|
+
let activeTriggers = 0;
|
|
252
|
+
let disabledTriggers = 0;
|
|
253
|
+
let durableExecutions = 0;
|
|
254
|
+
let durableFailures = 0;
|
|
255
|
+
let durableLastExecAt;
|
|
256
|
+
for (const task of tasks) {
|
|
257
|
+
const trigger = readTriggerConfig(task);
|
|
258
|
+
if (!trigger) continue;
|
|
259
|
+
if (trigger.enabled) activeTriggers += 1;
|
|
260
|
+
else disabledTriggers += 1;
|
|
261
|
+
const runs = readTriggerRuns(task);
|
|
262
|
+
for (const run of runs) {
|
|
263
|
+
durableExecutions += 1;
|
|
264
|
+
if (run.status === "error") durableFailures += 1;
|
|
265
|
+
if (!durableLastExecAt || run.finishedAt > durableLastExecAt) durableLastExecAt = run.finishedAt;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const inMemory = getMetrics(runtime.agentId);
|
|
269
|
+
return {
|
|
270
|
+
triggersEnabled: triggersFeatureEnabled(runtime),
|
|
271
|
+
activeTriggers,
|
|
272
|
+
disabledTriggers,
|
|
273
|
+
totalExecutions: Math.max(inMemory.totalExecutions, durableExecutions),
|
|
274
|
+
totalFailures: Math.max(inMemory.totalFailures, durableFailures),
|
|
275
|
+
totalSkipped: inMemory.totalSkipped,
|
|
276
|
+
lastExecutionAt: inMemory.lastExecutionAt ?? durableLastExecAt
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
//#endregion
|
|
281
|
+
export { TRIGGER_TASK_NAME, TRIGGER_TASK_TAGS, executeTriggerTask, getTriggerHealthSnapshot, getTriggerLimit, listTriggerTasks, readTriggerConfig, readTriggerRuns, registerTriggerTaskWorker, taskToTriggerSummary, triggersFeatureEnabled };
|