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 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
//#region src/api/permissions-routes.ts
|
|
2
|
+
async function handlePermissionRoutes(ctx) {
|
|
3
|
+
const { req, res, method, pathname, state, readJsonBody, json, error, saveConfig, scheduleRuntimeRestart } = ctx;
|
|
4
|
+
if (!pathname.startsWith("/api/permissions")) return false;
|
|
5
|
+
if (method === "GET" && pathname === "/api/permissions") {
|
|
6
|
+
json(res, {
|
|
7
|
+
permissions: state.permissionStates ?? {},
|
|
8
|
+
platform: process.platform,
|
|
9
|
+
shellEnabled: state.shellEnabled ?? true
|
|
10
|
+
});
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
if (method === "GET" && pathname === "/api/permissions/shell") {
|
|
14
|
+
const enabled = state.shellEnabled ?? true;
|
|
15
|
+
if (!state.permissionStates) state.permissionStates = {};
|
|
16
|
+
const shellState = state.permissionStates.shell;
|
|
17
|
+
const permission = {
|
|
18
|
+
id: "shell",
|
|
19
|
+
status: enabled ? "granted" : "denied",
|
|
20
|
+
lastChecked: shellState?.lastChecked ?? Date.now(),
|
|
21
|
+
canRequest: false
|
|
22
|
+
};
|
|
23
|
+
state.permissionStates.shell = permission;
|
|
24
|
+
json(res, {
|
|
25
|
+
enabled,
|
|
26
|
+
...permission,
|
|
27
|
+
permission
|
|
28
|
+
});
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
if (method === "GET" && pathname.startsWith("/api/permissions/")) {
|
|
32
|
+
const permId = pathname.slice(17);
|
|
33
|
+
if (!permId || permId.includes("/")) {
|
|
34
|
+
error(res, "Invalid permission ID", 400);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
const permState = (state.permissionStates ?? {})[permId];
|
|
38
|
+
if (!permState) {
|
|
39
|
+
json(res, {
|
|
40
|
+
id: permId,
|
|
41
|
+
status: "not-applicable",
|
|
42
|
+
lastChecked: Date.now(),
|
|
43
|
+
canRequest: false
|
|
44
|
+
});
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
json(res, permState);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
if (method === "POST" && pathname === "/api/permissions/refresh") {
|
|
51
|
+
json(res, {
|
|
52
|
+
message: "Permission refresh requested",
|
|
53
|
+
action: "ipc:permissions:refresh"
|
|
54
|
+
});
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
if (method === "POST" && pathname.match(/^\/api\/permissions\/[^/]+\/request$/)) {
|
|
58
|
+
const permId = pathname.split("/")[3];
|
|
59
|
+
json(res, {
|
|
60
|
+
message: `Permission request for ${permId}`,
|
|
61
|
+
action: `ipc:permissions:request:${permId}`
|
|
62
|
+
});
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
if (method === "POST" && pathname.match(/^\/api\/permissions\/[^/]+\/open-settings$/)) {
|
|
66
|
+
const permId = pathname.split("/")[3];
|
|
67
|
+
json(res, {
|
|
68
|
+
message: `Opening settings for ${permId}`,
|
|
69
|
+
action: `ipc:permissions:openSettings:${permId}`
|
|
70
|
+
});
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
if (method === "PUT" && pathname === "/api/permissions/shell") {
|
|
74
|
+
const body = await readJsonBody(req, res);
|
|
75
|
+
if (!body) return true;
|
|
76
|
+
const enabled = body.enabled === true;
|
|
77
|
+
state.shellEnabled = enabled;
|
|
78
|
+
if (!state.permissionStates) state.permissionStates = {};
|
|
79
|
+
state.permissionStates.shell = {
|
|
80
|
+
id: "shell",
|
|
81
|
+
status: enabled ? "granted" : "denied",
|
|
82
|
+
lastChecked: Date.now(),
|
|
83
|
+
canRequest: false
|
|
84
|
+
};
|
|
85
|
+
if (!state.config.features) state.config.features = {};
|
|
86
|
+
state.config.features.shellEnabled = enabled;
|
|
87
|
+
saveConfig(state.config);
|
|
88
|
+
if (state.runtime) scheduleRuntimeRestart(`Shell access ${enabled ? "enabled" : "disabled"}`);
|
|
89
|
+
json(res, {
|
|
90
|
+
shellEnabled: enabled,
|
|
91
|
+
permission: state.permissionStates.shell
|
|
92
|
+
});
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
if (method === "PUT" && pathname === "/api/permissions/state") {
|
|
96
|
+
const body = await readJsonBody(req, res);
|
|
97
|
+
if (!body) return true;
|
|
98
|
+
if (body.permissions && typeof body.permissions === "object") state.permissionStates = body.permissions;
|
|
99
|
+
json(res, {
|
|
100
|
+
updated: true,
|
|
101
|
+
permissions: state.permissionStates
|
|
102
|
+
});
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
export { handlePermissionRoutes };
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//#region src/api/plugin-validation.ts
|
|
2
|
+
const KEY_PREFIX_HINTS = {
|
|
3
|
+
ANTHROPIC_API_KEY: {
|
|
4
|
+
prefix: "sk-ant-",
|
|
5
|
+
label: "Anthropic"
|
|
6
|
+
},
|
|
7
|
+
OPENAI_API_KEY: {
|
|
8
|
+
prefix: "sk-",
|
|
9
|
+
label: "OpenAI"
|
|
10
|
+
},
|
|
11
|
+
GROQ_API_KEY: {
|
|
12
|
+
prefix: "gsk_",
|
|
13
|
+
label: "Groq"
|
|
14
|
+
},
|
|
15
|
+
XAI_API_KEY: {
|
|
16
|
+
prefix: "xai-",
|
|
17
|
+
label: "xAI"
|
|
18
|
+
},
|
|
19
|
+
OPENROUTER_API_KEY: {
|
|
20
|
+
prefix: "sk-or-",
|
|
21
|
+
label: "OpenRouter"
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Validate a plugin's configuration.
|
|
26
|
+
*
|
|
27
|
+
* Checks all required parameters (from the plugin's package.json metadata)
|
|
28
|
+
* and applies format-specific warnings for known API key patterns.
|
|
29
|
+
*
|
|
30
|
+
* @param pluginId - The plugin identifier (e.g. "anthropic", "discord")
|
|
31
|
+
* @param category - Plugin category
|
|
32
|
+
* @param envKey - Primary environment variable key (legacy, used as fallback)
|
|
33
|
+
* @param configKeys - All known config key names for this plugin
|
|
34
|
+
* @param providedConfig - Config values being set (for PUT validation)
|
|
35
|
+
* @param paramDefs - Full parameter definitions with required/sensitive metadata
|
|
36
|
+
*/
|
|
37
|
+
function validatePluginConfig(_pluginId, _category, envKey, configKeys, providedConfig, paramDefs) {
|
|
38
|
+
const errors = [];
|
|
39
|
+
const warnings = [];
|
|
40
|
+
const allowedConfigKeys = new Set(configKeys);
|
|
41
|
+
const canonicalKeyByNormalized = new Map(configKeys.map((key) => [key.trim().toUpperCase(), key]));
|
|
42
|
+
if (providedConfig) for (const key of Object.keys(providedConfig)) {
|
|
43
|
+
if (allowedConfigKeys.has(key)) continue;
|
|
44
|
+
const canonical = canonicalKeyByNormalized.get(key.trim().toUpperCase());
|
|
45
|
+
if (canonical) {
|
|
46
|
+
errors.push({
|
|
47
|
+
field: key,
|
|
48
|
+
message: `${key} does not match declared config key casing; use ${canonical}`
|
|
49
|
+
});
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
errors.push({
|
|
53
|
+
field: key,
|
|
54
|
+
message: `${key} is not a declared config key for this plugin`
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (paramDefs && paramDefs.length > 0) for (const param of paramDefs) {
|
|
58
|
+
if (!param.required) continue;
|
|
59
|
+
const value = providedConfig?.[param.key] ?? process.env[param.key];
|
|
60
|
+
if (!value || !value.trim()) {
|
|
61
|
+
if (param.default) warnings.push({
|
|
62
|
+
field: param.key,
|
|
63
|
+
message: `${param.key} is not set (will use default: ${param.default})`
|
|
64
|
+
});
|
|
65
|
+
else errors.push({
|
|
66
|
+
field: param.key,
|
|
67
|
+
message: `${param.key} is required but not set`
|
|
68
|
+
});
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const hint = KEY_PREFIX_HINTS[param.key];
|
|
72
|
+
if (hint && !value.startsWith(hint.prefix)) warnings.push({
|
|
73
|
+
field: param.key,
|
|
74
|
+
message: `${hint.label} key should start with "${hint.prefix}" — the current value may be invalid`
|
|
75
|
+
});
|
|
76
|
+
if (param.sensitive && value.trim().length < 10) warnings.push({
|
|
77
|
+
field: param.key,
|
|
78
|
+
message: `${param.key} looks too short (${value.trim().length} chars)`
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else if (envKey) {
|
|
82
|
+
const currentValue = providedConfig?.[envKey] ?? process.env[envKey];
|
|
83
|
+
if (!currentValue || !currentValue.trim()) errors.push({
|
|
84
|
+
field: envKey,
|
|
85
|
+
message: `${envKey} is required but not set`
|
|
86
|
+
});
|
|
87
|
+
else {
|
|
88
|
+
const hint = KEY_PREFIX_HINTS[envKey];
|
|
89
|
+
if (hint && !currentValue.startsWith(hint.prefix)) warnings.push({
|
|
90
|
+
field: envKey,
|
|
91
|
+
message: `${hint.label} key should start with "${hint.prefix}" — the current value may be invalid`
|
|
92
|
+
});
|
|
93
|
+
if (currentValue.trim().length < 10) warnings.push({
|
|
94
|
+
field: envKey,
|
|
95
|
+
message: `${envKey} looks too short (${currentValue.trim().length} chars)`
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
valid: errors.length === 0,
|
|
101
|
+
errors,
|
|
102
|
+
warnings
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
//#endregion
|
|
107
|
+
export { validatePluginConfig };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
//#region src/plugins/whatsapp/actions.ts
|
|
2
|
+
const sendWhatsAppMessage = {
|
|
3
|
+
name: "SEND_WHATSAPP_MESSAGE",
|
|
4
|
+
description: "Send a text message to a phone number on WhatsApp. Use this when the user asks you to send a WhatsApp message to someone.",
|
|
5
|
+
similes: [
|
|
6
|
+
"WHATSAPP_MESSAGE",
|
|
7
|
+
"TEXT_ON_WHATSAPP",
|
|
8
|
+
"MESSAGE_ON_WHATSAPP",
|
|
9
|
+
"SEND_WHATSAPP",
|
|
10
|
+
"WA_MESSAGE"
|
|
11
|
+
],
|
|
12
|
+
parameters: [{
|
|
13
|
+
name: "phoneNumber",
|
|
14
|
+
description: "The recipient's phone number in international format (e.g. +1234567890). Include country code.",
|
|
15
|
+
required: true,
|
|
16
|
+
schema: { type: "string" }
|
|
17
|
+
}, {
|
|
18
|
+
name: "message",
|
|
19
|
+
description: "The text message to send.",
|
|
20
|
+
required: true,
|
|
21
|
+
schema: { type: "string" }
|
|
22
|
+
}],
|
|
23
|
+
validate: async (runtime, _message) => {
|
|
24
|
+
return runtime.hasService("whatsapp");
|
|
25
|
+
},
|
|
26
|
+
handler: async (runtime, message, _state, options, callback) => {
|
|
27
|
+
const params = options?.parameters;
|
|
28
|
+
const phoneNumber = params?.phoneNumber;
|
|
29
|
+
const messageText = params?.message;
|
|
30
|
+
if (!phoneNumber || !messageText) {
|
|
31
|
+
runtime.logger.warn("[whatsapp] SEND_WHATSAPP_MESSAGE missing phoneNumber or message params");
|
|
32
|
+
if (callback) await callback({
|
|
33
|
+
text: "I need both a phone number and a message to send on WhatsApp.",
|
|
34
|
+
actions: []
|
|
35
|
+
});
|
|
36
|
+
return { success: false };
|
|
37
|
+
}
|
|
38
|
+
const cleanPhone = phoneNumber.replace(/[^0-9]/g, "");
|
|
39
|
+
if (cleanPhone.length < 8) {
|
|
40
|
+
if (callback) await callback({
|
|
41
|
+
text: `The phone number "${phoneNumber}" doesn't look valid. Please include the country code (e.g. +1234567890).`,
|
|
42
|
+
actions: []
|
|
43
|
+
});
|
|
44
|
+
return { success: false };
|
|
45
|
+
}
|
|
46
|
+
const jid = `${cleanPhone}@s.whatsapp.net`;
|
|
47
|
+
try {
|
|
48
|
+
await runtime.sendMessageToTarget({
|
|
49
|
+
source: "whatsapp",
|
|
50
|
+
channelId: jid,
|
|
51
|
+
roomId: message.roomId
|
|
52
|
+
}, { text: messageText });
|
|
53
|
+
runtime.logger.info(`[whatsapp] Sent message to +${cleanPhone} via SEND_WHATSAPP_MESSAGE action`);
|
|
54
|
+
if (callback) await callback({
|
|
55
|
+
text: `Message sent to +${cleanPhone} on WhatsApp.`,
|
|
56
|
+
actions: []
|
|
57
|
+
});
|
|
58
|
+
return { success: true };
|
|
59
|
+
} catch (err) {
|
|
60
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
61
|
+
runtime.logger.error(`[whatsapp] Failed to send WhatsApp message: ${errMsg}`);
|
|
62
|
+
if (callback) await callback({
|
|
63
|
+
text: `Failed to send WhatsApp message: ${errMsg}`,
|
|
64
|
+
actions: []
|
|
65
|
+
});
|
|
66
|
+
return { success: false };
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
examples: [[{
|
|
70
|
+
name: "{{user1}}",
|
|
71
|
+
content: { text: "Send a WhatsApp message to +1234567890 saying hello, how are you?" }
|
|
72
|
+
}, {
|
|
73
|
+
name: "{{agent}}",
|
|
74
|
+
content: {
|
|
75
|
+
text: "I'll send that WhatsApp message now.",
|
|
76
|
+
actions: ["SEND_WHATSAPP_MESSAGE"]
|
|
77
|
+
}
|
|
78
|
+
}], [{
|
|
79
|
+
name: "{{user1}}",
|
|
80
|
+
content: { text: "Text my friend on WhatsApp at +1234567890 and tell them I'll be late" }
|
|
81
|
+
}, {
|
|
82
|
+
name: "{{agent}}",
|
|
83
|
+
content: {
|
|
84
|
+
text: "Sending the message on WhatsApp.",
|
|
85
|
+
actions: ["SEND_WHATSAPP_MESSAGE"]
|
|
86
|
+
}
|
|
87
|
+
}]]
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
export { sendWhatsAppMessage };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { WhatsAppBaileysService } from "./service.js";
|
|
2
|
+
import { sendWhatsAppMessage } from "./actions.js";
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/whatsapp/index.ts
|
|
5
|
+
const whatsappPlugin = {
|
|
6
|
+
name: "whatsapp",
|
|
7
|
+
description: "WhatsApp messaging via Baileys (QR code auth)",
|
|
8
|
+
services: [WhatsAppBaileysService],
|
|
9
|
+
actions: [sendWhatsAppMessage],
|
|
10
|
+
init: async (_config, runtime) => {
|
|
11
|
+
runtime.logger.info("[whatsapp] Plugin initialized");
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
export { whatsappPlugin as default, whatsappPlugin };
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import { Service, createUniqueUuid } from "@elizaos/core";
|
|
5
|
+
|
|
6
|
+
//#region src/plugins/whatsapp/service.ts
|
|
7
|
+
/**
|
|
8
|
+
* WhatsApp Baileys service for ElizaOS runtime.
|
|
9
|
+
*
|
|
10
|
+
* Manages a persistent Baileys socket using QR-auth credentials saved to disk
|
|
11
|
+
* by the pairing service (`src/services/whatsapp-pairing.ts`).
|
|
12
|
+
*
|
|
13
|
+
* Handles:
|
|
14
|
+
* - Outbound messages via `registerSendHandler("whatsapp", ...)`
|
|
15
|
+
* - Inbound messages via `messages.upsert` → `emitEvent(MESSAGE_RECEIVED)`
|
|
16
|
+
* - Auto-reconnect on transient disconnects
|
|
17
|
+
*/
|
|
18
|
+
function resolveAuthDir(runtime) {
|
|
19
|
+
const customDir = runtime.getSetting("WHATSAPP_AUTH_DIR");
|
|
20
|
+
if (customDir && typeof customDir === "string" && customDir.trim()) return customDir.trim();
|
|
21
|
+
const workspaceDir = process.env.MILADY_WORKSPACE_DIR ?? path.join(os.homedir(), ".milady", "workspace");
|
|
22
|
+
return path.join(workspaceDir, "whatsapp-auth", "default");
|
|
23
|
+
}
|
|
24
|
+
function extractMessageText(msg) {
|
|
25
|
+
const m = msg.message;
|
|
26
|
+
if (!m) return void 0;
|
|
27
|
+
if (typeof m.conversation === "string") return m.conversation;
|
|
28
|
+
const ext = m.extendedTextMessage;
|
|
29
|
+
if (ext && typeof ext.text === "string") return ext.text;
|
|
30
|
+
for (const key of [
|
|
31
|
+
"imageMessage",
|
|
32
|
+
"videoMessage",
|
|
33
|
+
"documentMessage"
|
|
34
|
+
]) {
|
|
35
|
+
const media = m[key];
|
|
36
|
+
if (media && typeof media.caption === "string") return media.caption;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function jidToPhoneNumber(jid) {
|
|
40
|
+
return jid.split("@")[0].split(":")[0];
|
|
41
|
+
}
|
|
42
|
+
var WhatsAppBaileysService = class WhatsAppBaileysService extends Service {
|
|
43
|
+
constructor(..._args) {
|
|
44
|
+
super(..._args);
|
|
45
|
+
this.capabilityDescription = "The agent can send and receive WhatsApp messages via Baileys";
|
|
46
|
+
this.sock = null;
|
|
47
|
+
this.phoneNumber = null;
|
|
48
|
+
this.connected = false;
|
|
49
|
+
this.reconnectDelay = 3e3;
|
|
50
|
+
this.reconnectTimer = null;
|
|
51
|
+
}
|
|
52
|
+
static {
|
|
53
|
+
this.serviceType = "whatsapp";
|
|
54
|
+
}
|
|
55
|
+
static async start(runtime) {
|
|
56
|
+
const service = new WhatsAppBaileysService(runtime);
|
|
57
|
+
await service.initialize();
|
|
58
|
+
return service;
|
|
59
|
+
}
|
|
60
|
+
static registerSendHandlers(runtime, service) {
|
|
61
|
+
const svc = service;
|
|
62
|
+
runtime.registerSendHandler("whatsapp", svc.handleSendMessage.bind(svc));
|
|
63
|
+
runtime.logger.info("[whatsapp] Registered send handler");
|
|
64
|
+
}
|
|
65
|
+
static async stopRuntime(runtime) {
|
|
66
|
+
const svc = runtime.getService("whatsapp");
|
|
67
|
+
if (svc) await svc.stop();
|
|
68
|
+
}
|
|
69
|
+
async initialize() {
|
|
70
|
+
const authDir = resolveAuthDir(this.runtime);
|
|
71
|
+
const credsPath = path.join(authDir, "creds.json");
|
|
72
|
+
if (!fs.existsSync(credsPath)) {
|
|
73
|
+
this.runtime.logger.warn("[whatsapp] No QR auth credentials found at " + credsPath + " — skipping Baileys connection. Pair via the WhatsApp connector settings first.");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
this.runtime.logger.info("[whatsapp] Auth credentials found, connecting to WhatsApp...");
|
|
77
|
+
const baileys = await import("@whiskeysockets/baileys");
|
|
78
|
+
const makeWASocket = baileys.default;
|
|
79
|
+
const { useMultiFileAuthState, fetchLatestBaileysVersion, DisconnectReason } = baileys;
|
|
80
|
+
const { Boom } = await import("@hapi/boom");
|
|
81
|
+
const pino = (await import("pino")).default;
|
|
82
|
+
const logger = pino({ level: "silent" });
|
|
83
|
+
const { state, saveCreds } = await useMultiFileAuthState(authDir);
|
|
84
|
+
const { version } = await fetchLatestBaileysVersion();
|
|
85
|
+
const connect = async () => {
|
|
86
|
+
this.sock = makeWASocket({
|
|
87
|
+
version,
|
|
88
|
+
auth: state,
|
|
89
|
+
logger,
|
|
90
|
+
printQRInTerminal: false,
|
|
91
|
+
browser: [
|
|
92
|
+
"Milady AI",
|
|
93
|
+
"Desktop",
|
|
94
|
+
"1.0.0"
|
|
95
|
+
]
|
|
96
|
+
});
|
|
97
|
+
this.sock.ev.on("creds.update", saveCreds);
|
|
98
|
+
this.sock.ev.on("connection.update", async (update) => {
|
|
99
|
+
const { connection, lastDisconnect } = update;
|
|
100
|
+
if (connection === "open") {
|
|
101
|
+
this.connected = true;
|
|
102
|
+
this.reconnectDelay = 3e3;
|
|
103
|
+
this.phoneNumber = this.sock?.user?.id?.split(":")[0] ?? null;
|
|
104
|
+
this.runtime.logger.info(`[whatsapp] Connected as +${this.phoneNumber ?? "unknown"}`);
|
|
105
|
+
}
|
|
106
|
+
if (connection === "close") {
|
|
107
|
+
this.connected = false;
|
|
108
|
+
const statusCode = (lastDisconnect?.error)?.output?.statusCode;
|
|
109
|
+
this.runtime.logger.info(`[whatsapp] Connection closed (code=${statusCode})`);
|
|
110
|
+
if (statusCode === DisconnectReason.loggedOut) {
|
|
111
|
+
this.runtime.logger.warn("[whatsapp] Logged out — device was removed from WhatsApp. Re-pair via QR to reconnect.");
|
|
112
|
+
this.sock = null;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (statusCode === DisconnectReason.restartRequired || statusCode === DisconnectReason.timedOut || statusCode === DisconnectReason.connectionClosed || statusCode === DisconnectReason.connectionReplaced) {
|
|
116
|
+
this.runtime.logger.info(`[whatsapp] Reconnecting after transient disconnect in ${this.reconnectDelay}ms...`);
|
|
117
|
+
const delay = this.reconnectDelay;
|
|
118
|
+
this.reconnectDelay = Math.min(this.reconnectDelay * 2, 6e4);
|
|
119
|
+
this.sock = null;
|
|
120
|
+
this.reconnectTimer = setTimeout(() => {
|
|
121
|
+
this.reconnectTimer = null;
|
|
122
|
+
connect().catch((err) => {
|
|
123
|
+
this.runtime.logger.error(`[whatsapp] Reconnect failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
124
|
+
});
|
|
125
|
+
}, delay);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
this.sock.ev.on("messages.upsert", async ({ messages, type }) => {
|
|
130
|
+
if (type !== "notify") return;
|
|
131
|
+
for (const msg of messages) try {
|
|
132
|
+
await this.handleIncomingMessage(msg);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
this.runtime.logger.error(`[whatsapp] Error handling incoming message: ${err instanceof Error ? err.message : String(err)}`);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
await connect();
|
|
139
|
+
}
|
|
140
|
+
async stop() {
|
|
141
|
+
this.runtime?.logger?.info("[whatsapp] Stopping service...");
|
|
142
|
+
if (this.reconnectTimer) {
|
|
143
|
+
clearTimeout(this.reconnectTimer);
|
|
144
|
+
this.reconnectTimer = null;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
this.sock?.end(void 0);
|
|
148
|
+
} catch {}
|
|
149
|
+
this.sock = null;
|
|
150
|
+
this.connected = false;
|
|
151
|
+
}
|
|
152
|
+
async handleSendMessage(runtime, target, content) {
|
|
153
|
+
if (!this.sock || !this.connected) throw new Error("WhatsApp is not connected. Pair via QR code first.");
|
|
154
|
+
let jid;
|
|
155
|
+
if (target.channelId) jid = target.channelId.includes("@") ? target.channelId : `${target.channelId}@s.whatsapp.net`;
|
|
156
|
+
else if (target.entityId) {
|
|
157
|
+
const cleaned = target.entityId.replace(/[^0-9]/g, "");
|
|
158
|
+
if (cleaned.length >= 8) jid = `${cleaned}@s.whatsapp.net`;
|
|
159
|
+
else throw new Error("Cannot determine WhatsApp recipient from target: " + JSON.stringify(target));
|
|
160
|
+
} else throw new Error("WhatsApp SendHandler requires channelId or entityId. Got: " + JSON.stringify(target));
|
|
161
|
+
const text = content.text ?? "";
|
|
162
|
+
if (!text.trim()) {
|
|
163
|
+
runtime.logger.warn("[whatsapp] Skipping empty message send");
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
runtime.logger.info(`[whatsapp] Sending message to ${jidToPhoneNumber(jid)}`);
|
|
167
|
+
await this.sock.sendMessage(jid, { text });
|
|
168
|
+
}
|
|
169
|
+
async handleIncomingMessage(msg) {
|
|
170
|
+
const key = msg.key;
|
|
171
|
+
if (!key) return;
|
|
172
|
+
if (key.fromMe) return;
|
|
173
|
+
const remoteJid = key.remoteJid;
|
|
174
|
+
if (!remoteJid || remoteJid === "status@broadcast") return;
|
|
175
|
+
if (remoteJid.endsWith("@g.us")) return;
|
|
176
|
+
const text = extractMessageText(msg);
|
|
177
|
+
if (!text || !text.trim()) return;
|
|
178
|
+
const senderPhone = jidToPhoneNumber(remoteJid);
|
|
179
|
+
this.runtime.logger.info(`[whatsapp] Incoming message from +${senderPhone}: "${text.slice(0, 50)}${text.length > 50 ? "..." : ""}"`);
|
|
180
|
+
const entityId = createUniqueUuid(this.runtime, remoteJid);
|
|
181
|
+
const roomId = createUniqueUuid(this.runtime, remoteJid);
|
|
182
|
+
const messageId = createUniqueUuid(this.runtime, key.id ?? `wa-${Date.now()}`);
|
|
183
|
+
const worldId = createUniqueUuid(this.runtime, "whatsapp-world");
|
|
184
|
+
await this.runtime.ensureConnection({
|
|
185
|
+
entityId,
|
|
186
|
+
roomId,
|
|
187
|
+
userName: senderPhone,
|
|
188
|
+
name: senderPhone,
|
|
189
|
+
source: "whatsapp",
|
|
190
|
+
channelId: remoteJid,
|
|
191
|
+
type: "DM",
|
|
192
|
+
worldId,
|
|
193
|
+
worldName: "WhatsApp"
|
|
194
|
+
});
|
|
195
|
+
const memory = {
|
|
196
|
+
id: messageId,
|
|
197
|
+
entityId,
|
|
198
|
+
agentId: this.runtime.agentId,
|
|
199
|
+
roomId,
|
|
200
|
+
content: {
|
|
201
|
+
text,
|
|
202
|
+
source: "whatsapp",
|
|
203
|
+
channelType: "DM"
|
|
204
|
+
},
|
|
205
|
+
metadata: {
|
|
206
|
+
type: "custom",
|
|
207
|
+
entityName: senderPhone,
|
|
208
|
+
fromId: remoteJid
|
|
209
|
+
},
|
|
210
|
+
createdAt: Date.now()
|
|
211
|
+
};
|
|
212
|
+
const callback = async (responseContent) => {
|
|
213
|
+
try {
|
|
214
|
+
if (responseContent.target && typeof responseContent.target === "string" && responseContent.target.toLowerCase() !== "whatsapp") return [];
|
|
215
|
+
const replyText = responseContent.text ?? "";
|
|
216
|
+
if (!replyText.trim()) return [];
|
|
217
|
+
await this.sock?.sendMessage(remoteJid, { text: replyText });
|
|
218
|
+
const replyMemory = {
|
|
219
|
+
id: createUniqueUuid(this.runtime, `wa-reply-${Date.now()}`),
|
|
220
|
+
entityId: this.runtime.agentId,
|
|
221
|
+
agentId: this.runtime.agentId,
|
|
222
|
+
roomId,
|
|
223
|
+
content: {
|
|
224
|
+
...responseContent,
|
|
225
|
+
text: replyText,
|
|
226
|
+
source: "whatsapp",
|
|
227
|
+
channelType: "DM",
|
|
228
|
+
inReplyTo: messageId
|
|
229
|
+
},
|
|
230
|
+
createdAt: Date.now()
|
|
231
|
+
};
|
|
232
|
+
await this.runtime.createMemory(replyMemory, "messages");
|
|
233
|
+
return [replyMemory];
|
|
234
|
+
} catch (err) {
|
|
235
|
+
this.runtime.logger.error(`[whatsapp] Error sending reply: ${err instanceof Error ? err.message : String(err)}`);
|
|
236
|
+
return [];
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const messagingAPI = this.getMessagingAPI();
|
|
240
|
+
const messageService = this.getMessageService();
|
|
241
|
+
if (messagingAPI) {
|
|
242
|
+
this.runtime.logger.debug("[whatsapp] Using messaging API for inbound message");
|
|
243
|
+
await messagingAPI.sendMessage(this.runtime.agentId, memory, { onResponse: callback });
|
|
244
|
+
} else if (messageService) {
|
|
245
|
+
this.runtime.logger.debug("[whatsapp] Using messageService for inbound message");
|
|
246
|
+
await messageService.handleMessage(this.runtime, memory, callback);
|
|
247
|
+
} else {
|
|
248
|
+
this.runtime.logger.debug("[whatsapp] Using event-based handling for inbound message");
|
|
249
|
+
await this.runtime.emitEvent(["MESSAGE_RECEIVED"], {
|
|
250
|
+
runtime: this.runtime,
|
|
251
|
+
message: memory,
|
|
252
|
+
callback,
|
|
253
|
+
source: "whatsapp"
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
getMessagingAPI() {
|
|
258
|
+
const rt = this.runtime;
|
|
259
|
+
if ("elizaOS" in rt && typeof rt.elizaOS === "object" && rt.elizaOS !== null && typeof rt.elizaOS.sendMessage === "function") return rt.elizaOS;
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
getMessageService() {
|
|
263
|
+
const svc = this.runtime.messageService;
|
|
264
|
+
if (svc && typeof svc.handleMessage === "function") return svc;
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
//#endregion
|
|
270
|
+
export { WhatsAppBaileysService };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { SUBSCRIPTION_PROVIDER_MAP } from "./auth/types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/api/provider-switch-config.ts
|
|
4
|
+
/**
|
|
5
|
+
* Apply subscription provider configuration to the config object.
|
|
6
|
+
*
|
|
7
|
+
* Sets `agents.defaults.subscriptionProvider` and `agents.defaults.model.primary`
|
|
8
|
+
* so the runtime auto-detects the correct provider on restart.
|
|
9
|
+
*
|
|
10
|
+
* Mutates `config` in place.
|
|
11
|
+
*/
|
|
12
|
+
function applySubscriptionProviderConfig(config, provider) {
|
|
13
|
+
config.agents ??= {};
|
|
14
|
+
config.agents.defaults ??= {};
|
|
15
|
+
const defaults = config.agents.defaults;
|
|
16
|
+
const subscriptionKey = provider === "openai-subscription" ? "openai-codex" : provider;
|
|
17
|
+
const modelProvider = SUBSCRIPTION_PROVIDER_MAP[subscriptionKey];
|
|
18
|
+
if (modelProvider) {
|
|
19
|
+
defaults.subscriptionProvider = subscriptionKey;
|
|
20
|
+
defaults.model = {
|
|
21
|
+
...defaults.model,
|
|
22
|
+
primary: modelProvider
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Clear subscription provider configuration from the config object.
|
|
28
|
+
*
|
|
29
|
+
* Removes `agents.defaults.subscriptionProvider` so the runtime
|
|
30
|
+
* doesn't try to auto-detect a subscription provider on restart.
|
|
31
|
+
*
|
|
32
|
+
* Mutates `config` in place.
|
|
33
|
+
*/
|
|
34
|
+
function clearSubscriptionProviderConfig(config) {
|
|
35
|
+
config.agents ??= {};
|
|
36
|
+
config.agents.defaults ??= {};
|
|
37
|
+
delete config.agents.defaults.subscriptionProvider;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
export { applySubscriptionProviderConfig, clearSubscriptionProviderConfig };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//#region src/providers/admin-trust.ts
|
|
2
|
+
function normalizeRole(role) {
|
|
3
|
+
return (role ?? "").toUpperCase();
|
|
4
|
+
}
|
|
5
|
+
const adminTrustProvider = createAdminTrustProvider();
|
|
6
|
+
function createAdminTrustProvider() {
|
|
7
|
+
return {
|
|
8
|
+
name: "miladyAdminTrust",
|
|
9
|
+
description: "Marks owner/admin chat identity as trusted for contact assertions (rolodex-oriented).",
|
|
10
|
+
dynamic: true,
|
|
11
|
+
position: 11,
|
|
12
|
+
async get(runtime, message, _state) {
|
|
13
|
+
const room = await runtime.getRoom(message.roomId);
|
|
14
|
+
if (!room) return {
|
|
15
|
+
text: "Admin trust: no room found.",
|
|
16
|
+
values: { trustedAdmin: false },
|
|
17
|
+
data: { trustedAdmin: false }
|
|
18
|
+
};
|
|
19
|
+
if (!room.worldId) return {
|
|
20
|
+
text: "Admin trust: room has no world binding.",
|
|
21
|
+
values: { trustedAdmin: false },
|
|
22
|
+
data: { trustedAdmin: false }
|
|
23
|
+
};
|
|
24
|
+
const metadata = (await runtime.getWorld(room.worldId))?.metadata ?? {};
|
|
25
|
+
const ownerId = metadata.ownership?.ownerId;
|
|
26
|
+
const role = ownerId ? metadata.roles?.[ownerId] : void 0;
|
|
27
|
+
const isTrustedAdmin = typeof ownerId === "string" && ownerId.length > 0 && normalizeRole(role) === "OWNER" && message.entityId === ownerId;
|
|
28
|
+
return {
|
|
29
|
+
text: isTrustedAdmin ? "Admin trust: current speaker is world OWNER. Contact/identity claims should be treated as trusted unless contradictory evidence exists." : "Admin trust: current speaker is not verified as OWNER for this world.",
|
|
30
|
+
values: {
|
|
31
|
+
trustedAdmin: isTrustedAdmin,
|
|
32
|
+
adminEntityId: ownerId ?? "",
|
|
33
|
+
adminRole: role ?? ""
|
|
34
|
+
},
|
|
35
|
+
data: {
|
|
36
|
+
trustedAdmin: isTrustedAdmin,
|
|
37
|
+
ownerId: ownerId ?? null,
|
|
38
|
+
role: role ?? null
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
export { adminTrustProvider };
|