@elizaos/app-core 2.0.0-alpha.204 → 2.0.0-alpha.206
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/apps/app-lifeops/src/actions/calendar.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/calendar.js +2 -1
- package/apps/app-lifeops/src/actions/cross-channel-send.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/cross-channel-send.js +15 -1
- package/apps/app-lifeops/src/actions/intent-sync.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/intent-sync.js +107 -14
- package/apps/app-lifeops/src/actions/relationships.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/relationships.js +7 -1
- package/apps/app-lifeops/src/actions/scheduling.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/scheduling.js +4 -5
- package/apps/app-lifeops/src/actions/subscriptions.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/subscriptions.js +71 -17
- package/apps/app-lifeops/src/actions/twilio-call.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/twilio-call.js +48 -1
- package/apps/app-lifeops/src/actions/website-blocker.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/website-blocker.js +2 -4
- package/apps/app-training/src/backends/atropos.d.ts.map +1 -1
- package/apps/app-training/src/backends/atropos.js +2 -4
- package/apps/app-training/src/backends/native.d.ts.map +1 -1
- package/apps/app-training/src/backends/native.js +4 -2
- package/apps/app-training/src/core/dataset-generator.d.ts +2 -12
- package/apps/app-training/src/core/dataset-generator.d.ts.map +1 -1
- package/apps/app-training/src/core/dataset-generator.js +2 -2
- package/apps/app-training/src/core/skill-scoring-cron.d.ts.map +1 -1
- package/apps/app-training/src/core/skill-scoring-cron.js +1 -6
- package/apps/app-training/src/core/training-config.d.ts.map +1 -1
- package/apps/app-training/src/core/training-config.js +1 -6
- package/apps/app-training/src/core/trajectory-export-cron.d.ts.map +1 -1
- package/apps/app-training/src/core/trajectory-export-cron.js +1 -6
- package/apps/app-training/src/optimizers/index.d.ts +1 -1
- package/apps/app-training/src/optimizers/index.d.ts.map +1 -1
- package/apps/app-training/src/optimizers/index.js +1 -1
- package/apps/app-training/src/optimizers/scoring.d.ts +19 -0
- package/apps/app-training/src/optimizers/scoring.d.ts.map +1 -1
- package/apps/app-training/src/optimizers/scoring.js +35 -1
- package/apps/app-training/src/services/training-service-like.d.ts +3 -2
- package/apps/app-training/src/services/training-service-like.d.ts.map +1 -1
- package/package.json +5 -5
- package/packages/agent/src/actions/skill-command.js +1 -1
- package/packages/agent/src/api/binance-skill-helpers.d.ts.map +1 -1
- package/packages/agent/src/api/binance-skill-helpers.js +6 -5
- package/packages/agent/src/api/chat-augmentation.d.ts.map +1 -1
- package/packages/agent/src/api/chat-augmentation.js +24 -12
- package/packages/agent/src/api/curated-skills-routes.d.ts.map +1 -1
- package/packages/agent/src/api/curated-skills-routes.js +1 -6
- package/packages/agent/src/api/onboarding-routes.d.ts.map +1 -1
- package/packages/agent/src/api/onboarding-routes.js +38 -5
- package/packages/agent/src/api/provider-switch-config.d.ts.map +1 -1
- package/packages/agent/src/api/provider-switch-config.js +6 -0
- package/packages/agent/src/api/server-types.d.ts +3 -2
- package/packages/agent/src/api/server-types.d.ts.map +1 -1
- package/packages/agent/src/api/skills-routes.d.ts.map +1 -1
- package/packages/agent/src/api/skills-routes.js +3 -47
- package/packages/agent/src/providers/skill-provider.js +2 -2
- package/packages/agent/src/runtime/eliza.js +1 -1
- package/packages/app-core/src/api/client-agent.d.ts +1 -0
- package/packages/app-core/src/api/client-agent.d.ts.map +1 -1
- package/packages/app-core/src/api/client-agent.js +68 -0
- package/packages/app-core/src/api/client-skills.d.ts +0 -3
- package/packages/app-core/src/api/client-skills.d.ts.map +1 -1
- package/packages/app-core/src/api/client-skills.js +0 -6
- package/packages/app-core/src/components/onboarding/FeaturesStep.d.ts.map +1 -1
- package/packages/app-core/src/components/onboarding/FeaturesStep.js +1 -1
- package/packages/app-core/src/components/onboarding/connection/ConnectionProviderDetailScreen.d.ts.map +1 -1
- package/packages/app-core/src/components/onboarding/connection/ConnectionProviderDetailScreen.js +1 -1
- package/packages/app-core/src/components/onboarding/connection/ConnectionProviderGridScreen.d.ts.map +1 -1
- package/packages/app-core/src/components/onboarding/connection/ConnectionProviderGridScreen.js +1 -1
- package/packages/app-core/src/components/pages/AppsView.d.ts.map +1 -1
- package/packages/app-core/src/components/pages/AppsView.js +8 -7
- package/packages/app-core/src/components/pages/LogsView.js +2 -2
- package/packages/app-core/src/onboarding-config.d.ts.map +1 -1
- package/packages/app-core/src/onboarding-config.js +17 -14
- package/packages/app-core/src/state/useOnboardingCallbacks.d.ts.map +1 -1
- package/packages/app-core/src/state/useOnboardingCallbacks.js +8 -0
- package/packages/app-core/src/state/usePluginsSkillsState.d.ts.map +1 -1
- package/packages/app-core/src/state/usePluginsSkillsState.js +3 -1
- package/packages/skills/src/resolver.d.ts.map +1 -1
- package/packages/skills/src/resolver.js +14 -4
- package/packages/typescript/src/features/advanced-capabilities/evaluators/skillExtraction.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/evaluators/skillExtraction.js +1 -6
- package/packages/typescript/src/features/advanced-capabilities/evaluators/skillRefinement.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/evaluators/skillRefinement.js +1 -5
- package/packages/typescript/src/generated/action-docs.d.ts +0 -10
- package/packages/typescript/src/generated/action-docs.d.ts.map +1 -1
- package/packages/typescript/src/generated/action-docs.js +0 -21
- package/packages/typescript/src/index.node.d.ts +1 -0
- package/packages/typescript/src/index.node.d.ts.map +1 -1
- package/packages/typescript/src/index.node.js +2 -0
- package/packages/typescript/src/services/optimized-prompt.d.ts.map +1 -1
- package/packages/typescript/src/services/optimized-prompt.js +1 -7
- package/packages/typescript/src/utils/state-dir.d.ts +19 -0
- package/packages/typescript/src/utils/state-dir.d.ts.map +1 -0
- package/packages/typescript/src/utils/state-dir.js +24 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/calendar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAKN,aAAa,EACb,MAAM,EACN,KAAK,EACN,MAAM,eAAe,CAAC;AAyCvB,KAAK,iBAAiB,GAClB,MAAM,GACN,YAAY,GACZ,eAAe,GACf,cAAc,GACd,cAAc,GACd,cAAc,GACd,aAAa,CAAC;AAuBlB,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAkjDF,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,MAAM,EAAE,MAAM,EACd,QAAQ,SAA2B,GAClC,OAAO,CAAC,eAAe,CAAC,CA6J1B;AA2gCD,eAAO,MAAM,cAAc,EAAE,MAAM,GAAG;IACpC,8BAA8B,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/calendar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAKN,aAAa,EACb,MAAM,EACN,KAAK,EACN,MAAM,eAAe,CAAC;AAyCvB,KAAK,iBAAiB,GAClB,MAAM,GACN,YAAY,GACZ,eAAe,GACf,cAAc,GACd,cAAc,GACd,cAAc,GACd,aAAa,CAAC;AAuBlB,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAkjDF,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,MAAM,EAAE,MAAM,EACd,QAAQ,SAA2B,GAClC,OAAO,CAAC,eAAe,CAAC,CA6J1B;AA2gCD,eAAO,MAAM,cAAc,EAAE,MAAM,GAAG;IACpC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAoqC1C,CAAC"}
|
|
@@ -2126,7 +2126,8 @@ export const calendarAction = {
|
|
|
2126
2126
|
"DO NOT use this action when the user is only making an observation like 'my calendar has been crazy this quarter' unless they actually ask you to inspect or change calendar state. " +
|
|
2127
2127
|
"DO NOT use this action for email inbox work, drafting or sending emails — use GMAIL_ACTION instead. " +
|
|
2128
2128
|
"DO NOT use this action for personal habits, goals, routines, or reminders — use LIFE instead. " +
|
|
2129
|
-
"This action provides the final grounded reply; do not pair it with a speculative REPLY action."
|
|
2129
|
+
"This action provides the final grounded reply; do not pair it with a speculative REPLY action." +
|
|
2130
|
+
" DO NOT use this action when the user asks to 'help schedule' / 'set up' / 'find a time for' a meeting with a person or team without a specific time — that is SCHEDULING (subaction start). DO NOT use this action to 'propose', 'suggest', or 'offer' meeting time slots — that is PROPOSE_MEETING_TIMES. Use CALENDAR_ACTION only when the user specifies (or intends to specify) a concrete date/time for the event.",
|
|
2130
2131
|
descriptionCompressed: "Google Calendar via LifeOps: view schedule, search events, create events, query travel. Not for email or habits.",
|
|
2131
2132
|
suppressPostActionContinuation: true,
|
|
2132
2133
|
validate: async (runtime, message) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cross-channel-send.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/cross-channel-send.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EACV,MAAM,EAMP,MAAM,eAAe,CAAC;AAyBvB,eAAO,MAAM,2BAA2B,yIAY9B,CAAC;AACX,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAwZnF,eAAO,MAAM,sBAAsB,EAAE,MAAM,GAAG;IAC5C,8BAA8B,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"cross-channel-send.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/cross-channel-send.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EACV,MAAM,EAMP,MAAM,eAAe,CAAC;AAyBvB,eAAO,MAAM,2BAA2B,yIAY9B,CAAC;AACX,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAwZnF,eAAO,MAAM,sBAAsB,EAAE,MAAM,GAAG;IAC5C,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAoN1C,CAAC"}
|
|
@@ -390,10 +390,24 @@ export const crossChannelSendAction = {
|
|
|
390
390
|
"DRAFT_MESSAGE",
|
|
391
391
|
"SEND_ACROSS_CHANNEL",
|
|
392
392
|
"SEND_MESSAGE",
|
|
393
|
+
"POST_TO_CHANNEL",
|
|
394
|
+
"POST_TO_DISCORD",
|
|
395
|
+
"POST_TO_SLACK",
|
|
396
|
+
"SEND_TELEGRAM",
|
|
397
|
+
"SEND_SIGNAL",
|
|
398
|
+
"SEND_WHATSAPP",
|
|
399
|
+
"SEND_IMESSAGE",
|
|
400
|
+
"SEND_SMS",
|
|
393
401
|
],
|
|
394
402
|
description: "Draft or send a message across any connected channel (email, telegram, " +
|
|
395
403
|
"discord, signal, sms, twilio_voice, imessage, whatsapp, notifications). Always " +
|
|
396
|
-
"drafts first; caller must re-invoke with confirmed: true to dispatch."
|
|
404
|
+
"drafts first; caller must re-invoke with confirmed: true to dispatch. " +
|
|
405
|
+
"Use this for any 'post <msg> to <channel>', 'send <msg> on <platform>', " +
|
|
406
|
+
"or 'dm <person> on <platform>' request — the channel name in the sentence " +
|
|
407
|
+
"(discord, telegram, signal, etc.) is the strongest signal. " +
|
|
408
|
+
"Do NOT use SCHEDULING for channel-send requests even if the message " +
|
|
409
|
+
"mentions a meeting-like word (e.g. 'standup', 'sync'); SCHEDULING is for " +
|
|
410
|
+
"negotiating calendar proposals, not relaying chat messages.",
|
|
397
411
|
suppressPostActionContinuation: true,
|
|
398
412
|
validate: async (runtime, message) => hasAdminAccess(runtime, message),
|
|
399
413
|
parameters: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent-sync.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/intent-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAMP,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"intent-sync.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/intent-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAMP,MAAM,eAAe,CAAC;AA+JvB,eAAO,MAAM,gBAAgB,EAAE,MAiR9B,CAAC"}
|
|
@@ -43,6 +43,78 @@ function fail(error, extra = {}) {
|
|
|
43
43
|
data: { actionName: ACTION_NAME, error, ...extra },
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
|
+
// Validation terminates the turn cleanly: success: true at the ActionResult
|
|
47
|
+
// level (so the orchestrator does not retry), but values.success: false so
|
|
48
|
+
// downstream consumers see the logical failure. Carries descriptive text.
|
|
49
|
+
function validationTerminate(error, text, extra = {}) {
|
|
50
|
+
return {
|
|
51
|
+
text,
|
|
52
|
+
success: true,
|
|
53
|
+
values: { success: false, error, ...extra },
|
|
54
|
+
data: { actionName: ACTION_NAME, error, ...extra },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// Parse flat key=value params that arrive as a raw string instead of nested
|
|
58
|
+
// XML/JSON. Handles quoted and unquoted values.
|
|
59
|
+
function parseFlatParams(raw) {
|
|
60
|
+
const out = {};
|
|
61
|
+
const re = /(\w+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s]+))/g;
|
|
62
|
+
let m;
|
|
63
|
+
while ((m = re.exec(raw)) !== null) {
|
|
64
|
+
out[m[1]] = m[2] ?? m[3] ?? m[4] ?? "";
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
// Tolerate a wider shape: if `params` is a string (or carries a rawParams
|
|
69
|
+
// blob), attempt flat parsing and merge into a typed object.
|
|
70
|
+
function normalizeParams(raw) {
|
|
71
|
+
if (typeof raw === "string") {
|
|
72
|
+
return parseFlatParams(raw);
|
|
73
|
+
}
|
|
74
|
+
if (raw && typeof raw === "object") {
|
|
75
|
+
const obj = raw;
|
|
76
|
+
const merged = { ...obj };
|
|
77
|
+
const rawParams = obj.rawParams ?? obj.raw;
|
|
78
|
+
if (typeof rawParams === "string") {
|
|
79
|
+
const parsed = parseFlatParams(rawParams);
|
|
80
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
81
|
+
if (merged[k] === undefined)
|
|
82
|
+
merged[k] = v;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return merged;
|
|
86
|
+
}
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
function inferSubactionFromText(text) {
|
|
90
|
+
const t = text.toLowerCase();
|
|
91
|
+
if (/\b(broadcast|send|publish|push|ping)\b/.test(t))
|
|
92
|
+
return "broadcast";
|
|
93
|
+
if (/\b(list|show|what.*pending)\b/.test(t))
|
|
94
|
+
return "list_pending";
|
|
95
|
+
if (/\b(acknowledge|ack|mark\s+done)\b/.test(t))
|
|
96
|
+
return "acknowledge";
|
|
97
|
+
if (/\b(prune|expire|clean)\b/.test(t))
|
|
98
|
+
return "prune_expired";
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
function inferKindFromText(text) {
|
|
102
|
+
const t = text.toLowerCase();
|
|
103
|
+
if (/\b(reminder|stretch|break|vitamin|hydrate|water|walk)\b/.test(t)) {
|
|
104
|
+
if (isKind("routine_reminder"))
|
|
105
|
+
return "routine_reminder";
|
|
106
|
+
}
|
|
107
|
+
if (/\b(urgent|help|need)\b/.test(t)) {
|
|
108
|
+
if (isKind("attention_request"))
|
|
109
|
+
return "attention_request";
|
|
110
|
+
}
|
|
111
|
+
if (/\b(request|ask|please)\b/.test(t)) {
|
|
112
|
+
if (isKind("user_action_requested")) {
|
|
113
|
+
return "user_action_requested";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
46
118
|
export const intentSyncAction = {
|
|
47
119
|
name: ACTION_NAME,
|
|
48
120
|
similes: ["BROADCAST_INTENT", "SYNC_INTENT", "CROSS_DEVICE_INTENT"],
|
|
@@ -161,26 +233,47 @@ export const intentSyncAction = {
|
|
|
161
233
|
if (!(await hasAdminAccess(runtime, message))) {
|
|
162
234
|
return fail("PERMISSION_DENIED");
|
|
163
235
|
}
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
236
|
+
const rawParams = options?.parameters;
|
|
237
|
+
const params = normalizeParams(rawParams);
|
|
238
|
+
const messageText = typeof message.content?.text === "string" ? message.content.text : "";
|
|
239
|
+
let subactionRaw = coerceString(params.subaction);
|
|
240
|
+
if (!subactionRaw) {
|
|
241
|
+
// Tolerate LLMs that emit the verb in `intent` / `mode` / plain text.
|
|
242
|
+
subactionRaw =
|
|
243
|
+
coerceString(params.mode) ??
|
|
244
|
+
coerceString(params.action) ??
|
|
245
|
+
inferSubactionFromText(messageText);
|
|
246
|
+
}
|
|
247
|
+
if (!subactionRaw) {
|
|
248
|
+
return validationTerminate("MISSING_SUBACTION", "I couldn't tell whether you wanted to broadcast, list, acknowledge, or prune an intent. Please say which.");
|
|
249
|
+
}
|
|
168
250
|
if (!isSubaction(subactionRaw)) {
|
|
169
|
-
return
|
|
251
|
+
return validationTerminate("UNKNOWN_SUBACTION", `Unknown INTENT_SYNC subaction "${subactionRaw}". Expected one of: ${SUBACTIONS.join(", ")}.`, { subaction: subactionRaw });
|
|
170
252
|
}
|
|
171
253
|
const subaction = subactionRaw;
|
|
172
254
|
if (subaction === "broadcast") {
|
|
173
|
-
|
|
255
|
+
let kindRaw = coerceString(params.kind);
|
|
256
|
+
if (!kindRaw || !isKind(kindRaw)) {
|
|
257
|
+
// Only infer when the current value is clearly wrong/missing — not
|
|
258
|
+
// when it's already a valid kind.
|
|
259
|
+
const inferred = inferKindFromText(messageText);
|
|
260
|
+
if (inferred)
|
|
261
|
+
kindRaw = inferred;
|
|
262
|
+
}
|
|
174
263
|
const title = coerceString(params.title);
|
|
175
264
|
const body = coerceString(params.body);
|
|
176
|
-
if (!kindRaw)
|
|
177
|
-
return
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if (!
|
|
183
|
-
return
|
|
265
|
+
if (!kindRaw) {
|
|
266
|
+
return validationTerminate("MISSING_KIND", `I need an intent kind to broadcast (one of: ${LIFE_INTENT_KINDS.join(", ")}).`);
|
|
267
|
+
}
|
|
268
|
+
if (!isKind(kindRaw)) {
|
|
269
|
+
return validationTerminate("UNKNOWN_KIND", `Unknown intent kind "${kindRaw}". Expected one of: ${LIFE_INTENT_KINDS.join(", ")}.`, { kind: kindRaw });
|
|
270
|
+
}
|
|
271
|
+
if (!title) {
|
|
272
|
+
return validationTerminate("MISSING_TITLE", "I need a short title for the intent before I can broadcast it.");
|
|
273
|
+
}
|
|
274
|
+
if (!body) {
|
|
275
|
+
return validationTerminate("MISSING_BODY", "I need a body for the intent before I can broadcast it.");
|
|
276
|
+
}
|
|
184
277
|
const targetRaw = coerceString(params.target) ?? "all";
|
|
185
278
|
if (!isTarget(targetRaw)) {
|
|
186
279
|
return fail("UNKNOWN_TARGET", { target: targetRaw });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/relationships.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,MAAM,EAMP,MAAM,eAAe,CAAC;AA+XvB,eAAO,MAAM,kBAAkB,EAAE,MAAM,GAAG;IACxC,8BAA8B,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/relationships.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,MAAM,EAMP,MAAM,eAAe,CAAC;AA+XvB,eAAO,MAAM,kBAAkB,EAAE,MAAM,GAAG;IACxC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAua1C,CAAC"}
|
|
@@ -270,13 +270,19 @@ function formatRelationshipLine(rel) {
|
|
|
270
270
|
export const relationshipAction = {
|
|
271
271
|
name: "RELATIONSHIP",
|
|
272
272
|
similes: [
|
|
273
|
+
"RELATIONSHIPS",
|
|
273
274
|
"CONTACT",
|
|
275
|
+
"CONTACTS",
|
|
274
276
|
"ROLODEX",
|
|
275
277
|
"FOLLOW_UP",
|
|
278
|
+
"FOLLOW_UPS",
|
|
276
279
|
"LOG_INTERACTION",
|
|
277
280
|
"ADD_CONTACT",
|
|
281
|
+
"DAYS_SINCE",
|
|
282
|
+
"LAST_CONTACTED",
|
|
278
283
|
],
|
|
279
|
-
description: "Manage contacts, relationships, and follow-ups. Subactions: list_contacts, add_contact, log_interaction, add_follow_up, complete_follow_up, follow_up_list, days_since."
|
|
284
|
+
description: "Manage contacts, relationships, and follow-ups. Subactions: list_contacts, add_contact, log_interaction, add_follow_up, complete_follow_up, follow_up_list, days_since." +
|
|
285
|
+
" Use for 'remind me to follow up with <person> [when]', 'add a follow-up with <person>', 'schedule a check-in with <person>' — subaction: add_follow_up. Use for 'how long since I talked to <person>' — subaction: days_since. Use for 'who do I need to follow up with' — subaction: follow_up_list.",
|
|
280
286
|
suppressPostActionContinuation: true,
|
|
281
287
|
validate: async (runtime, message) => hasLifeOpsAccess(runtime, message),
|
|
282
288
|
handler: async (runtime, message, state, options, callback) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduling.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/scheduling.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,MAAM,EAOP,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAO9E,OAAO,EAIL,KAAK,yBAAyB,EAG/B,MAAM,6BAA6B,CAAC;AAUrC,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAkGF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,GAAG,EAAE,IAAI,CAAC;IACV,WAAW,EAAE,IAAI,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,yBAAyB,CAAC;IACvC,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACzC,GAAG,mBAAmB,EAAE,CAwExB;AAiCD,eAAO,MAAM,yBAAyB,EAAE,MAAM,GAAG;IAC/C,8BAA8B,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"scheduling.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/scheduling.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,MAAM,EAOP,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAO9E,OAAO,EAIL,KAAK,yBAAyB,EAG/B,MAAM,6BAA6B,CAAC;AAUrC,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAkGF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,GAAG,EAAE,IAAI,CAAC;IACV,WAAW,EAAE,IAAI,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,yBAAyB,CAAC;IACvC,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACzC,GAAG,mBAAmB,EAAE,CAwExB;AAiCD,eAAO,MAAM,yBAAyB,EAAE,MAAM,GAAG;IAC/C,8BAA8B,CAAC,EAAE,OAAO,CAAC;CA8J1C,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,MAoGrC,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,MAAM,GAAG;IACpD,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAqI1C,CAAC;AAsLF,eAAO,MAAM,gBAAgB,EAAE,MAyS9B,CAAC"}
|
|
@@ -185,16 +185,14 @@ export const proposeMeetingTimesAction = {
|
|
|
185
185
|
"BUNDLE_MEETINGS_WHILE_TRAVELING",
|
|
186
186
|
],
|
|
187
187
|
tags: [
|
|
188
|
-
"always-include",
|
|
189
188
|
"meeting slots",
|
|
190
|
-
"bundle meetings",
|
|
191
|
-
"travel scheduling",
|
|
192
189
|
"reschedule options",
|
|
193
190
|
],
|
|
194
191
|
description: "Propose candidate meeting time slots to offer to another person. " +
|
|
195
192
|
"Reads the owner's calendar busy times and meeting preferences " +
|
|
196
193
|
"(preferred hours, blackout windows, travel buffer) and returns " +
|
|
197
|
-
"three available slots by default over the next seven days. Use this for bundled scheduling while traveling or when you need concrete reschedule options."
|
|
194
|
+
"three available slots by default over the next seven days. Use this for bundled scheduling while traveling or when you need concrete reschedule options." +
|
|
195
|
+
" DO NOT use for small talk, weather, general conversation, or vague mentions of travel. Only fire when the user explicitly asks to propose / suggest / offer time slots to another person (e.g. 'propose three times for a meeting with Marco').",
|
|
198
196
|
suppressPostActionContinuation: true,
|
|
199
197
|
validate: async (runtime, message) => hasLifeOpsAccess(runtime, message),
|
|
200
198
|
handler: async (runtime, message, _state, options, callback) => {
|
|
@@ -670,7 +668,8 @@ export const schedulingAction = {
|
|
|
670
668
|
"Do not use this for first-turn calendar requests, recurring blocks, " +
|
|
671
669
|
"travel-time bundling, missed-call repair, or fresh candidate-slot " +
|
|
672
670
|
"searches; those belong to CALENDAR_ACTION, PROPOSE_MEETING_TIMES, INBOX, " +
|
|
673
|
-
"or CROSS_CHANNEL_SEND."
|
|
671
|
+
"or CROSS_CHANNEL_SEND." +
|
|
672
|
+
" Use for 'help me schedule a meeting with <person/team>', 'set up a sync with <person>', 'find a time with <team>' — subaction: start. Use for 'propose N times for a sync with <person>' — subaction: propose.",
|
|
674
673
|
suppressPostActionContinuation: true,
|
|
675
674
|
validate: async (runtime, message) => hasAdminAccess(runtime, message),
|
|
676
675
|
handler: async (runtime, message, state, options, callback) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAOP,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAOP,MAAM,eAAe,CAAC;AAoUvB,eAAO,MAAM,mBAAmB,EAAE,MAAM,GAAG;IACzC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAuC1C,CAAC"}
|
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
import { hasLifeOpsAccess, INTERNAL_URL } from "./lifeops-google-helpers.js";
|
|
2
2
|
import { LifeOpsService, LifeOpsServiceError } from "../lifeops/service.js";
|
|
3
|
+
// Pre-seeded catalog of common subscription services so the cancel flow can
|
|
4
|
+
// resolve a user-friendly name like "Netflix" to a slug even when the live
|
|
5
|
+
// candidate audit has not populated the catalog yet.
|
|
6
|
+
const KNOWN_SUBSCRIPTION_SERVICES = {
|
|
7
|
+
netflix: { slug: "netflix", displayName: "Netflix", cancelUrl: "https://www.netflix.com/cancelplan" },
|
|
8
|
+
hulu: { slug: "hulu", displayName: "Hulu", cancelUrl: "https://www.hulu.com/account/cancel" },
|
|
9
|
+
disneyplus: { slug: "disney-plus", displayName: "Disney+", cancelUrl: "https://www.disneyplus.com/account/subscription" },
|
|
10
|
+
spotify: { slug: "spotify", displayName: "Spotify", cancelUrl: "https://www.spotify.com/account/subscription/" },
|
|
11
|
+
appletv: { slug: "apple-tv", displayName: "Apple TV+", cancelUrl: "https://tv.apple.com/account" },
|
|
12
|
+
youtubepremium: { slug: "youtube-premium", displayName: "YouTube Premium", cancelUrl: "https://www.youtube.com/paid_memberships" },
|
|
13
|
+
amazonprime: { slug: "amazon-prime", displayName: "Amazon Prime", cancelUrl: "https://www.amazon.com/gp/help/customer/display.html?nodeId=GKTRKLHHK7AJBJXE" },
|
|
14
|
+
applemusic: { slug: "apple-music", displayName: "Apple Music", cancelUrl: "https://music.apple.com/account/manage" },
|
|
15
|
+
hbomax: { slug: "hbo-max", displayName: "HBO Max", cancelUrl: "https://help.hbomax.com/us/article/cancellation-help" },
|
|
16
|
+
max: { slug: "hbo-max", displayName: "Max", cancelUrl: "https://help.hbomax.com/us/article/cancellation-help" },
|
|
17
|
+
paramountplus: { slug: "paramount-plus", displayName: "Paramount+", cancelUrl: "https://www.paramountplus.com/account/" },
|
|
18
|
+
peacock: { slug: "peacock", displayName: "Peacock", cancelUrl: "https://www.peacocktv.com/account/plan" },
|
|
19
|
+
};
|
|
20
|
+
function lookupKnownService(name) {
|
|
21
|
+
if (!name)
|
|
22
|
+
return null;
|
|
23
|
+
const normalized = name.toLowerCase().replace(/[\s+\-_]+/g, "");
|
|
24
|
+
return KNOWN_SUBSCRIPTION_SERVICES[normalized] ?? null;
|
|
25
|
+
}
|
|
3
26
|
const ACTION_NAME = "SUBSCRIPTIONS";
|
|
4
27
|
function messageText(message) {
|
|
5
28
|
return typeof message.content?.text === "string" ? message.content.text : "";
|
|
@@ -95,23 +118,54 @@ async function runSubscriptionsAction(runtime, message, state, options) {
|
|
|
95
118
|
};
|
|
96
119
|
}
|
|
97
120
|
case "cancel": {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
121
|
+
const known = lookupKnownService(serviceName ?? serviceSlug);
|
|
122
|
+
const resolvedSlug = serviceSlug ?? known?.slug ?? null;
|
|
123
|
+
const resolvedName = serviceName ?? known?.displayName ?? null;
|
|
124
|
+
try {
|
|
125
|
+
const summary = await service.cancelSubscription({
|
|
126
|
+
candidateId: params.candidateId ?? null,
|
|
127
|
+
serviceName: resolvedName,
|
|
128
|
+
serviceSlug: resolvedSlug,
|
|
129
|
+
executor: params.executor ?? inferred.executor ?? null,
|
|
130
|
+
confirmed: parseConfirmed(text, params),
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
success: summary.cancellation.status !== "failed" &&
|
|
134
|
+
summary.cancellation.status !== "unsupported_surface",
|
|
135
|
+
text: service.summarizeSubscriptionCancellation(summary),
|
|
136
|
+
data: {
|
|
137
|
+
cancellation: summary.cancellation,
|
|
138
|
+
candidate: summary.candidate,
|
|
139
|
+
browserTask: browserTaskData(summary),
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
// If the service catalog can't resolve the candidate, fall back to
|
|
145
|
+
// the pre-seeded known-service map and hand off to computer-use.
|
|
146
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
147
|
+
if (known && /candidate|serviceName|serviceSlug/i.test(msg)) {
|
|
148
|
+
return {
|
|
149
|
+
success: true,
|
|
150
|
+
text: `I don't have an active subscription record for ${known.displayName} yet, but I know the cancellation URL ` +
|
|
151
|
+
`(${known.cancelUrl ?? "not on file"}). I'll need to drive the browser to cancel it — ` +
|
|
152
|
+
`shall I continue with LIFEOPS_COMPUTER_USE?`,
|
|
153
|
+
values: {
|
|
154
|
+
success: false,
|
|
155
|
+
handoff: "LIFEOPS_COMPUTER_USE",
|
|
156
|
+
service: known.slug,
|
|
157
|
+
cancelUrl: known.cancelUrl ?? null,
|
|
158
|
+
},
|
|
159
|
+
data: {
|
|
160
|
+
handoff: "LIFEOPS_COMPUTER_USE",
|
|
161
|
+
service: known.slug,
|
|
162
|
+
displayName: known.displayName,
|
|
163
|
+
cancelUrl: known.cancelUrl ?? null,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
throw err;
|
|
168
|
+
}
|
|
115
169
|
}
|
|
116
170
|
case "status": {
|
|
117
171
|
const summary = await service.getSubscriptionCancellationStatus({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"twilio-call.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/twilio-call.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAMZ,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"twilio-call.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/twilio-call.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAMZ,MAAM,eAAe,CAAC;AAmEvB,eAAO,MAAM,gBAAgB,EAAE,MA4M9B,CAAC;AA6BF,iBAAS,eAAe,CACtB,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CAAE,GAAG,SAAS,GAC7D,MAAM,GAAG,IAAI,CAUf;AAED,iBAAS,qBAAqB,CAC5B,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CAAE,GAAG,SAAS,GAC7D,MAAM,EAAE,CAiBV;AA0BD,eAAO,MAAM,cAAc,EAAE,MAAM,GAAG;IACpC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CA0I1C,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,MAAM,GAAG;IACxC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CA4N1C,CAAC;AAGF,eAAO,MAAM,UAAU;;;CAGtB,CAAC"}
|
|
@@ -15,6 +15,35 @@ function coerceBool(value) {
|
|
|
15
15
|
return value.toLowerCase() === "true";
|
|
16
16
|
return false;
|
|
17
17
|
}
|
|
18
|
+
// E.164: leading +, 1-15 digits total, first digit non-zero.
|
|
19
|
+
const E164_RE = /^\+[1-9]\d{1,14}$/;
|
|
20
|
+
// All-5s placeholder (the classic "555" fake number, with common punctuation).
|
|
21
|
+
const PLACEHOLDER_555_RE = /^\+?1?[-\s]?\(?5{3}\)?[-\s]?5{3}[-\s]?5{4}$/;
|
|
22
|
+
function isE164(value) {
|
|
23
|
+
return E164_RE.test(value);
|
|
24
|
+
}
|
|
25
|
+
function isPlaceholderOrNonNumeric(value) {
|
|
26
|
+
if (PLACEHOLDER_555_RE.test(value))
|
|
27
|
+
return true;
|
|
28
|
+
// any letter indicates a natural-language phrase like "owner's cable company"
|
|
29
|
+
if (/[a-zA-Z]/.test(value))
|
|
30
|
+
return true;
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
function invalidPhoneResult(to, contact, actionName, errorCode) {
|
|
34
|
+
const subject = contact ?? "this contact";
|
|
35
|
+
const text = errorCode === "PLACEHOLDER_PHONE_NUMBER"
|
|
36
|
+
? `"${to}" looks like a placeholder phone number. Please share the real E.164 number (e.g. +15551234567) for ${subject} before I can place the call.`
|
|
37
|
+
: `I need a valid phone number in E.164 format (e.g. +15551234567) to place the call. Please confirm the number for ${subject}.`;
|
|
38
|
+
return {
|
|
39
|
+
text,
|
|
40
|
+
// success: true so the agent loop treats the turn as complete and does
|
|
41
|
+
// not silently retry the handler.
|
|
42
|
+
success: true,
|
|
43
|
+
values: { success: false, error: errorCode, to, contact: contact ?? null },
|
|
44
|
+
data: { actionName, error: errorCode, to, contact: contact ?? null },
|
|
45
|
+
};
|
|
46
|
+
}
|
|
18
47
|
export const twilioCallAction = {
|
|
19
48
|
name: ACTION_NAME,
|
|
20
49
|
similes: [
|
|
@@ -123,6 +152,12 @@ export const twilioCallAction = {
|
|
|
123
152
|
data: { actionName: ACTION_NAME },
|
|
124
153
|
};
|
|
125
154
|
}
|
|
155
|
+
if (isPlaceholderOrNonNumeric(to)) {
|
|
156
|
+
return invalidPhoneResult(to, undefined, ACTION_NAME, "PLACEHOLDER_PHONE_NUMBER");
|
|
157
|
+
}
|
|
158
|
+
if (!isE164(to)) {
|
|
159
|
+
return invalidPhoneResult(to, undefined, ACTION_NAME, "INVALID_PHONE_NUMBER");
|
|
160
|
+
}
|
|
126
161
|
if (!messageBody) {
|
|
127
162
|
return {
|
|
128
163
|
text: "Missing required parameter: message.",
|
|
@@ -307,6 +342,11 @@ export const callUserAction = {
|
|
|
307
342
|
},
|
|
308
343
|
};
|
|
309
344
|
}
|
|
345
|
+
if (!isE164(to) || isPlaceholderOrNonNumeric(to)) {
|
|
346
|
+
return invalidPhoneResult(to, "the owner", "CALL_USER", isPlaceholderOrNonNumeric(to)
|
|
347
|
+
? "PLACEHOLDER_PHONE_NUMBER"
|
|
348
|
+
: "INVALID_PHONE_NUMBER");
|
|
349
|
+
}
|
|
310
350
|
const credentials = readTwilioCredentialsFromEnv();
|
|
311
351
|
if (!credentials) {
|
|
312
352
|
return {
|
|
@@ -406,14 +446,21 @@ export const callExternalAction = {
|
|
|
406
446
|
}
|
|
407
447
|
const params = options?.parameters ?? {};
|
|
408
448
|
const to = params.to?.trim();
|
|
449
|
+
const contact = params.contact?.trim();
|
|
409
450
|
if (!to) {
|
|
410
451
|
return {
|
|
411
452
|
text: "Who should I call, or which saved contact/phone number should I use?",
|
|
412
|
-
success:
|
|
453
|
+
success: true,
|
|
413
454
|
values: { success: false, error: "MISSING_RECIPIENT" },
|
|
414
455
|
data: { actionName: "CALL_EXTERNAL", error: "MISSING_RECIPIENT" },
|
|
415
456
|
};
|
|
416
457
|
}
|
|
458
|
+
if (isPlaceholderOrNonNumeric(to)) {
|
|
459
|
+
return invalidPhoneResult(to, contact, "CALL_EXTERNAL", "PLACEHOLDER_PHONE_NUMBER");
|
|
460
|
+
}
|
|
461
|
+
if (!isE164(to)) {
|
|
462
|
+
return invalidPhoneResult(to, contact, "CALL_EXTERNAL", "INVALID_PHONE_NUMBER");
|
|
463
|
+
}
|
|
417
464
|
if (params.confirmed !== true) {
|
|
418
465
|
logger.info({ action: "CALL_EXTERNAL", to }, "[CALL_EXTERNAL] confirmation required");
|
|
419
466
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"website-blocker.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/website-blocker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAKP,MAAM,eAAe,CAAC;AAsPvB,eAAO,MAAM,mBAAmB,EAAE,MAAM,GAAG;IACzC,8BAA8B,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"website-blocker.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/website-blocker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAKP,MAAM,eAAe,CAAC;AAsPvB,eAAO,MAAM,mBAAmB,EAAE,MAAM,GAAG;IACzC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAuQ1C,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,MAuDzC,CAAC;AAEF,eAAO,MAAM,sCAAsC,EAAE,MA8DpD,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,MA6FnC,CAAC;AAEF,eAAO,MAAM,8BAA8B;qCAjeR,OAAO;CAieuB,CAAC;AAClE,eAAO,MAAM,0BAA0B,QAA8B,CAAC;AACtE,eAAO,MAAM,kCAAkC,QACP,CAAC;AACzC,eAAO,MAAM,gCAAgC,QAAwB,CAAC"}
|
|
@@ -187,16 +187,14 @@ export const blockWebsitesAction = {
|
|
|
187
187
|
"START_FOCUS_BLOCK",
|
|
188
188
|
"BLOCK_SITE",
|
|
189
189
|
"BLOCK_DISTRACTING_SITES",
|
|
190
|
-
"FOCUS_BLOCK",
|
|
191
|
-
"BLOCK_SOCIAL_MEDIA",
|
|
192
|
-
"SOCIAL_MEDIA_BLOCK",
|
|
193
190
|
],
|
|
194
191
|
description: "Admin-only. Start a local website block by editing the system hosts file. " +
|
|
195
192
|
"Use this for fixed-duration or generic focus blocks like 'block twitter and reddit for the next 2 hours', 'turn on a focus block for all social media sites', or 'block youtube'. " +
|
|
196
193
|
"Use recent conversation context to block public websites like x.com for a fixed duration or until manually unblocked. " +
|
|
197
194
|
"Do not use this when the unblock condition is finishing a task, workout, or todo; that is BLOCK_UNTIL_TASK_COMPLETE. " +
|
|
198
195
|
"Always drafts first; the owner must pass confirmed: true (e.g. by replying 'confirm') to actually edit the hosts file. " +
|
|
199
|
-
"If the user confirms a block in a follow-up message without repeating the hostnames, reuse that context through the action planner."
|
|
196
|
+
"If the user confirms a block in a follow-up message without repeating the hostnames, reuse that context through the action planner." +
|
|
197
|
+
" DO NOT use this action when the user references apps, games, or things 'on my phone' / 'on my device' — use BLOCK_APPS for those. Do not pair this action with a speculative REPLY; this action provides the final reply itself.",
|
|
200
198
|
descriptionCompressed: "Admin: block websites via hosts file for set duration.",
|
|
201
199
|
suppressPostActionContinuation: true,
|
|
202
200
|
validate: async (runtime, message) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atropos.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-training/src/backends/atropos.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"atropos.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-training/src/backends/atropos.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH,MAAM,WAAW,qBAAqB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,oBAAoB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AASD,wBAAsB,iBAAiB,CACtC,OAAO,EAAE,qBAAqB,GAC5B,OAAO,CAAC,oBAAoB,CAAC,CAoC/B"}
|
|
@@ -16,16 +16,14 @@
|
|
|
16
16
|
import { mkdirSync, copyFileSync, existsSync } from "node:fs";
|
|
17
17
|
import { join, basename, resolve } from "node:path";
|
|
18
18
|
import { spawnSync } from "node:child_process";
|
|
19
|
+
import { resolveStateDir } from "@elizaos/core";
|
|
19
20
|
function resolveDataDir(override) {
|
|
20
21
|
if (override)
|
|
21
22
|
return override;
|
|
22
23
|
const fromEnv = process.env.ATROPOS_DATA_DIR?.trim();
|
|
23
24
|
if (fromEnv)
|
|
24
25
|
return fromEnv;
|
|
25
|
-
|
|
26
|
-
process.env.ELIZA_STATE_DIR?.trim() ||
|
|
27
|
-
join(process.env.HOME ?? "", ".milady");
|
|
28
|
-
return join(stateDir, "training", "atropos");
|
|
26
|
+
return join(resolveStateDir(), "training", "atropos");
|
|
29
27
|
}
|
|
30
28
|
export async function runAtroposBackend(options) {
|
|
31
29
|
if (!existsSync(options.datasetPath)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-training/src/backends/native.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAGN,KAAK,UAAU,EAEf,KAAK,aAAa,EAClB,KAAK,eAAe,
|
|
1
|
+
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-training/src/backends/native.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAGN,KAAK,UAAU,EAEf,KAAK,aAAa,EAClB,KAAK,eAAe,EAKpB,KAAK,eAAe,EACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAElF,MAAM,WAAW,oBAAoB;IACpC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,sBAAsB,CAAC;IAC7B,SAAS,EAAE,aAAa,CAAC;IACzB,kDAAkD;IAClD,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,OAAO,EAAE;QAAE,QAAQ,EAAE,eAAe,CAAA;KAAE,CAAC;IACvC,gCAAgC;IAChC,OAAO,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,aAAa,CAAC;IACzB,IAAI,EAAE,sBAAsB,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,EAAE,CAAC;CAChB;AAsFD,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,oBAAoB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CA6C9B;AAED,eAAO,MAAM,iBAAiB,EAAE,SAAS,aAAa,EAI5C,CAAC"}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { existsSync, readFileSync } from "node:fs";
|
|
19
19
|
import { basename } from "node:path";
|
|
20
|
-
import { createPromptScorer, createRuntimeAdapter, runBootstrapFewshot, runInstructionSearch, runPromptEvolution, } from "../optimizers/index.js";
|
|
20
|
+
import { createPromptScorer, createRuntimeAdapter, runBootstrapFewshot, runInstructionSearch, runPromptEvolution, scorePlannerAction, } from "../optimizers/index.js";
|
|
21
21
|
function parseJsonlDataset(path) {
|
|
22
22
|
if (!existsSync(path)) {
|
|
23
23
|
throw new Error(`[native-backend] dataset not found at ${path}`);
|
|
@@ -101,7 +101,9 @@ export async function runNativeBackend(options) {
|
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
const adapter = options.adapter ?? createRuntimeAdapter(options.runtime.useModel);
|
|
104
|
-
const scorer = createPromptScorer(adapter
|
|
104
|
+
const scorer = createPromptScorer(adapter, {
|
|
105
|
+
compare: options.task === "action_planner" ? scorePlannerAction : undefined,
|
|
106
|
+
});
|
|
105
107
|
const result = await dispatchOptimizer(options.optimizer, {
|
|
106
108
|
baselinePrompt: options.baselinePrompt,
|
|
107
109
|
dataset,
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* - Falls back to whichever is available
|
|
15
15
|
*/
|
|
16
16
|
import type { IAgentRuntime } from "@elizaos/core";
|
|
17
|
+
import type { Trajectory } from "@elizaos/agent/types/trajectory";
|
|
17
18
|
import type { AgentContext } from "./context-types.js";
|
|
18
19
|
import { type ScenarioBlueprint } from "./scenario-blueprints.js";
|
|
19
20
|
export interface TrainingSample {
|
|
@@ -120,16 +121,5 @@ export declare function exportToGeminiJSONL(samples: TrainingSample[], outputDir
|
|
|
120
121
|
* Export from existing Eliza trajectories to training format.
|
|
121
122
|
* Converts real trajectory data into the same JSONL format.
|
|
122
123
|
*/
|
|
123
|
-
export declare function exportTrajectoriesAsTraining(trajectories:
|
|
124
|
-
steps: Array<{
|
|
125
|
-
llmCalls: Array<{
|
|
126
|
-
purpose?: string;
|
|
127
|
-
systemPrompt?: string;
|
|
128
|
-
userPrompt?: string;
|
|
129
|
-
response?: string;
|
|
130
|
-
model?: string;
|
|
131
|
-
}>;
|
|
132
|
-
}>;
|
|
133
|
-
metadata?: Record<string, unknown>;
|
|
134
|
-
}>, agentName: string, outputPath: string): Promise<number>;
|
|
124
|
+
export declare function exportTrajectoriesAsTraining(trajectories: Trajectory[], agentName: string, outputPath: string): Promise<number>;
|
|
135
125
|
//# sourceMappingURL=dataset-generator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataset-generator.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-training/src/core/dataset-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"dataset-generator.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-training/src/core/dataset-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -680,8 +680,8 @@ export async function exportToGeminiJSONL(samples, outputDir) {
|
|
|
680
680
|
export async function exportTrajectoriesAsTraining(trajectories, agentName, outputPath) {
|
|
681
681
|
const examples = [];
|
|
682
682
|
for (const trajectory of trajectories) {
|
|
683
|
-
for (const step of trajectory.steps) {
|
|
684
|
-
for (const call of step.llmCalls) {
|
|
683
|
+
for (const step of trajectory.steps ?? []) {
|
|
684
|
+
for (const call of step.llmCalls ?? []) {
|
|
685
685
|
if (call.purpose === "should_respond" &&
|
|
686
686
|
call.systemPrompt &&
|
|
687
687
|
call.userPrompt &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-scoring-cron.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-training/src/core/skill-scoring-cron.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,UAAU,aAAa;IACrB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AA2BD,UAAU,WAAW;IACnB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,aAAa,CAAC,EAAE,CACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,KACzC,IAAI,CAAC;CACX;
|
|
1
|
+
{"version":3,"file":"skill-scoring-cron.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-training/src/core/skill-scoring-cron.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,UAAU,aAAa;IACrB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AA2BD,UAAU,WAAW;IACnB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,aAAa,CAAC,EAAE,CACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,KACzC,IAAI,CAAC;CACX;AAgCD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,OAAO,CAkDT;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GACrC,OAAO,CACR,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CACzE,CAwDA;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3C,OAAO,CAAC,IAAI,CAAC,CAkCf"}
|