Skip to content

Commit a1f12c5

Browse files
author
Shaw
committed
more lifeops changes
1 parent 9d2bcb7 commit a1f12c5

13 files changed

Lines changed: 570 additions & 371 deletions

File tree

packages/app-core/scripts/lib/patch-bun-exports.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ const ELIZA_CORE_STREAM_RETRY_PLACEHOLDER_BROWSER_FROM = `if(this.state="retryin
453453
const ELIZA_CORE_STREAM_RETRY_PLACEHOLDER_BROWSER_TO = `this.state="retrying";`;
454454

455455
/**
456-
* `ValidationStreamExtractor.signalRetry` in @elizaos/core calls `onChunk` with a
456+
* Older @elizaos/core structured stream retry handling called `onChunk` with a
457457
* fixed apology line for non-rich streaming consumers on every parse/validation
458458
* retry. That duplicates in the saved message (e.g. 3× with maxRetries 3).
459459
* Remove the placeholder; `emitEvent({ eventType: "retry_start" })` is unchanged.

packages/app-core/src/benchmark/mock-plugin.ts

Lines changed: 40 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,12 @@ function extractArithmeticAnswer(prompt: string): string | null {
7979
}
8080

8181
function buildReplyToon(answer: string): string {
82-
return `<response>
83-
<thought>Answering the benchmark question directly.</thought>
84-
<actions>REPLY</actions>
85-
<providers></providers>
86-
<text>${answer}</text>
87-
</response>`;
82+
return buildToonResponse("", {
83+
thought: "Answering the benchmark question directly.",
84+
actions: "REPLY",
85+
providers: "",
86+
text: answer,
87+
});
8888
}
8989

9090
function buildHyperliquidPlanToon(): string {
@@ -177,32 +177,27 @@ function buildAdhdBenchToon(prompt: string): string {
177177
const action = extractAdhdAction(prompt);
178178
const text = action === "REPLY" ? "Replying directly with the requested information." : `Selected ${action}`;
179179
if (["REPLY", "IGNORE", "NONE"].includes(action)) {
180-
return `<response>
181-
<thought>Selecting ${action} for this ADHDBench turn.</thought>
182-
<actions>${action}</actions>
183-
<providers>RECENT_MESSAGES,ENTITIES,KNOWLEDGE,ROLES</providers>
184-
<text>${text}</text>
185-
</response>`;
180+
return buildToonResponse(prompt, {
181+
thought: `Selecting ${action} for this ADHDBench turn.`,
182+
actions: action,
183+
providers: "RECENT_MESSAGES,ENTITIES,KNOWLEDGE,ROLES",
184+
text,
185+
});
186186
}
187-
return `<response>
188-
<thought>Selecting ${action} for this ADHDBench turn.</thought>
189-
<actions>BENCHMARK_ACTION</actions>
190-
<providers>RECENT_MESSAGES,ENTITIES,KNOWLEDGE,ROLES</providers>
191-
<text>${text}</text>
192-
<params>
193-
<BENCHMARK_ACTION>
194-
<command>${action}</command>
195-
</BENCHMARK_ACTION>
196-
</params>
197-
</response>`;
187+
return buildToonResponse(prompt, {
188+
thought: `Selecting ${action} for this ADHDBench turn.`,
189+
actions: "BENCHMARK_ACTION",
190+
providers: "RECENT_MESSAGES,ENTITIES,KNOWLEDGE,ROLES",
191+
text,
192+
params: `BENCHMARK_ACTION:\n command: ${action}`,
193+
});
198194
}
199195

200196
function extractValidationFields(prompt: string): Record<string, string> {
201197
const tags: Record<string, string> = {};
202198

203-
// Per-field validation tags (context check levels 0/1)
204199
const matches = prompt.matchAll(
205-
/<(code_[A-Za-z0-9_-]+_(?:start|end)|one_(?:initial|middle|end)_code|two_(?:initial|middle|end)_code)>([\s\S]*?)<\/\1>/g,
200+
/"(code_[A-Za-z0-9_-]+_(?:start|end)|one_(?:initial|middle|end)_code|two_(?:initial|middle|end)_code)"\s*:\s*"([^"]+)"/g,
206201
);
207202
for (const [, key, value] of matches) {
208203
tags[key] = value.trim();
@@ -212,7 +207,7 @@ function extractValidationFields(prompt: string): Record<string, string> {
212207
// "initial code: ...", "middle code: ...", "end code: ..."
213208
// and optionally "second initial code: ..." for the second checkpoint set.
214209
const checkpointMatches = prompt.matchAll(
215-
/(second\s+)?(initial|middle|end)\s+code:\s*([a-f0-9-]{16,})/gi,
210+
/(second\s+)?(initial|middle|end)\s+code:\s*([a-f0-9-]{8,})/gi,
216211
);
217212
for (const [, second, stage, value] of checkpointMatches) {
218213
const prefix = second ? "two" : "one";
@@ -231,10 +226,17 @@ function buildToonResponse(
231226
(entry): entry is [string, string] =>
232227
typeof entry[1] === "string" && entry[1].length > 0,
233228
);
234-
const body = entries
235-
.map(([key, value]) => `<${key}>${value}</${key}>`)
236-
.join("\n");
237-
return `<response>\n${body}\n</response>`;
229+
return entries.map(([key, value]) => renderToonField(key, value)).join("\n");
230+
}
231+
232+
function renderToonField(key: string, value: string): string {
233+
if (value.includes("\n")) {
234+
return `${key}:\n${value
235+
.split(/\r?\n/)
236+
.map((line) => ` ${line}`)
237+
.join("\n")}`;
238+
}
239+
return `${key}: ${value}`;
238240
}
239241

240242
function buildCompletion(prompt: string): string {
@@ -252,7 +254,7 @@ function buildCompletion(prompt: string): string {
252254
// multiStepDecisionTemplate
253255
if (
254256
prompt.includes("Determine the next step") &&
255-
prompt.includes("<isFinish>")
257+
prompt.includes("isFinish")
256258
) {
257259
return buildToonResponse(prompt, {
258260
thought: "The benchmark task can be completed in this step.",
@@ -295,24 +297,13 @@ function buildCompletion(prompt: string): string {
295297
return buildAdhdBenchToon(prompt);
296298
}
297299

298-
// Default message handler path (single-shot core)
299-
const validationTags = extractValidationFields(prompt);
300-
const validationToon = Object.entries(validationTags)
301-
.map(([key, value]) => `<${key}>${value}</${key}>`)
302-
.join("\n");
303-
304-
return `<response>
305-
<thought>Execute deterministic benchmark action using ${command}.</thought>
306-
<actions>BENCHMARK_ACTION</actions>
307-
<providers></providers>
308-
<text>Executed ${command}</text>
309-
<params>
310-
<BENCHMARK_ACTION>
311-
<command>${command}</command>
312-
</BENCHMARK_ACTION>
313-
</params>
314-
${validationToon}
315-
</response>`;
300+
return buildToonResponse(prompt, {
301+
thought: `Execute deterministic benchmark action using ${command}.`,
302+
actions: "BENCHMARK_ACTION",
303+
providers: "",
304+
text: `Executed ${command}`,
305+
params: `BENCHMARK_ACTION:\n command: ${command}`,
306+
});
316307
}
317308

318309
function mockTextModel(

packages/app-core/src/components/chat/MessageContent.tsx

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -68,36 +68,11 @@ type Segment =
6868
const CONFIG_RE = /\[CONFIG:([@\w][\w@./:-]*)\]/g;
6969
const FENCED_JSON_RE = /```(?:json)?\s*\n([\s\S]*?)```/g;
7070

71-
/**
72-
* Strip elizaOS action XML blocks (`<actions>...</actions>` and
73-
* `<params>...</params>`) from displayed text. These are framework
74-
* metadata, not user-facing content.
75-
*/
76-
const ACTION_XML_RE =
77-
/\s*<actions>[\s\S]*?(?:<\/actions>|$)\s*|\s*<params>[\s\S]*?(?:<\/params>|$)\s*/g;
78-
const HIDDEN_XML_BLOCK_RE =
71+
const HIDDEN_TAG_BLOCK_RE =
7972
/<(think|analysis|reasoning|scratchpad|tool_calls?|tools?)\b[^>]*>[\s\S]*?(?:<\/\1>|$)/gi;
8073

81-
function extractXmlTag(
82-
raw: string,
83-
tag: string,
84-
opts?: { allowPartial?: boolean },
85-
): string | null {
86-
const open = `<${tag}>`;
87-
const close = `</${tag}>`;
88-
const start = raw.indexOf(open);
89-
if (start < 0) return null;
90-
91-
const contentStart = start + open.length;
92-
const end = raw.indexOf(close, contentStart);
93-
if (end < 0) {
94-
return opts?.allowPartial ? raw.slice(contentStart) : null;
95-
}
96-
return raw.slice(contentStart, end);
97-
}
98-
9974
/**
100-
* Strip partial/incomplete XML tags at the end of a streaming text chunk.
75+
* Strip partial/incomplete hidden tags at the end of a streaming text chunk.
10176
* During streaming, the buffer may end mid-tag (e.g. `"Hello<thi"`,
10277
* `"Hello</respon"`, or just `"Hello<"`). These fragments are not
10378
* user-facing content and must be hidden from both the display and voice
@@ -111,30 +86,12 @@ export function normalizeDisplayText(text: string): string {
11186
let normalized =
11287
text.length > MAX_DISPLAY_LEN ? text.slice(0, MAX_DISPLAY_LEN) : text;
11388

114-
// Hide framework-selected actions and tool params from chat bubbles.
115-
normalized = normalized.replace(ACTION_XML_RE, "");
116-
normalized = normalized.replace(HIDDEN_XML_BLOCK_RE, " ");
117-
118-
// Some prompts emit structured XML wrappers like:
119-
// <response><thought>...</thought><text>...</text></response>
120-
// Show only the user-facing <text>, even while it is still streaming.
121-
if (normalized.includes("<response>")) {
122-
const wrappedText = extractXmlTag(normalized, "text", {
123-
allowPartial: true,
124-
});
125-
if (wrappedText !== null) {
126-
normalized = wrappedText;
127-
} else {
128-
return "";
129-
}
130-
}
131-
132-
// Drop any leftover wrapper tags without disturbing plain text.
133-
normalized = normalized.replace(/<\/?(response|text|thought)\b[^>]*>/gi, "");
89+
// Hide hidden reasoning/tool scratchpad blocks from chat bubbles.
90+
normalized = normalized.replace(HIDDEN_TAG_BLOCK_RE, " ");
13491

135-
// During streaming, a chunk may end mid-tag (e.g. "<thi", "</respon").
92+
// During streaming, a chunk may end mid-tag (e.g. "<thi").
13693
// Strip any incomplete opening or closing tag at the very end so the
137-
// user never sees raw XML fragments while tokens arrive.
94+
// user never sees hidden-tag fragments while tokens arrive.
13895
normalized = normalized.replace(TRAILING_PARTIAL_TAG_RE, "");
13996

14097
normalized = stripAssistantStageDirections(normalized);

packages/app-core/src/styles/styles.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,19 @@ electrobun-wgpu {
140140

141141
/* ── Global resets ──────────────────────────────────────────────────── */
142142

143+
html,
144+
body {
145+
width: 100%;
146+
height: 100%;
147+
margin: 0;
148+
overflow: hidden;
149+
overscroll-behavior: none;
150+
}
151+
143152
#root {
144153
display: flex;
145154
flex-direction: column;
155+
width: 100vw;
146156
height: 100vh;
147157
height: 100dvh;
148158
overflow: hidden;

plugins/app-2004scape/vitest.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const here = path.dirname(fileURLToPath(import.meta.url));
66
const repoRoot = path.resolve(here, "../..");
77

88
export default defineConfig({
9+
root: here,
910
resolve: {
1011
alias: {
1112
"@elizaos/core": path.join(repoRoot, "packages/core/src/index.ts"),

plugins/app-lifeops/src/actions/autofill.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
* credential.
2020
*/
2121

22-
import { extractActionParamsViaLlm } from "@elizaos/agent/actions/extract-params";
2322
import { hasOwnerAccess } from "@elizaos/agent/security/access";
2423
import {
2524
type Action,
@@ -29,6 +28,8 @@ import {
2928
type IAgentRuntime,
3029
logger,
3130
type Memory,
31+
ModelType,
32+
type State,
3233
} from "@elizaos/core";
3334
import {
3435
DEFAULT_AUTOFILL_WHITELIST,
@@ -38,6 +39,7 @@ import {
3839
} from "../lifeops/autofill-whitelist.js";
3940
import { requireFeatureEnabled } from "../lifeops/feature-flags.js";
4041
import { FeatureNotEnabledError } from "../lifeops/feature-flags.types.js";
42+
import { runLifeOpsToonModel } from "./lifeops-google-helpers.js";
4143

4244
const FIELD_PURPOSES = [
4345
"email",
@@ -48,6 +50,14 @@ const FIELD_PURPOSES = [
4850
] as const;
4951
type FieldPurpose = (typeof FIELD_PURPOSES)[number];
5052

53+
type AutofillSubaction = "request_fill" | "add_whitelist" | "list_whitelist";
54+
55+
type AutofillParameters = RequestFieldFillParameters &
56+
AddAutofillWhitelistParameters & {
57+
readonly subaction?: AutofillSubaction | string;
58+
readonly intent?: string;
59+
};
60+
5161
const WHITELIST_CACHE_KEY = "eliza:lifeops-autofill-whitelist";
5262
const DEVICE_BUS_URL_ENV = "ELIZA_DEVICE_BUS_URL";
5363
const DEVICE_BUS_TOKEN_ENV = "ELIZA_DEVICE_BUS_TOKEN";

plugins/app-lifeops/src/actions/cross-channel-send.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,7 @@ import type {
2525
MessageConnector,
2626
State,
2727
} from "@elizaos/core";
28-
import {
29-
ModelType,
30-
parseToonKeyValue,
31-
sendMessageAction,
32-
} from "@elizaos/core";
28+
import { ModelType, parseToonKeyValue, sendMessageAction } from "@elizaos/core";
3329
import {
3430
createCalendlySingleUseLink,
3531
readCalendlyCredentialsFromEnv,
@@ -310,8 +306,7 @@ async function resolveCrossChannelSendPlanWithLlm(args: {
310306
prompt,
311307
});
312308
const rawResponse = typeof result === "string" ? result : "";
313-
const parsed =
314-
parseToonKeyValue<Record<string, unknown>>(rawResponse);
309+
const parsed = parseToonKeyValue<Record<string, unknown>>(rawResponse);
315310
if (!parsed) {
316311
return {};
317312
}
@@ -501,13 +496,18 @@ async function dispatchViaSendMessageAction(
501496
}
502497
}
503498

504-
const result = await sendMessageAction.handler(ctx.runtime, ctx.message, ctx.state, {
505-
parameters: {
506-
source,
507-
target: ctx.target,
508-
message: ctx.body,
499+
const result = await sendMessageAction.handler(
500+
ctx.runtime,
501+
ctx.message,
502+
ctx.state,
503+
{
504+
parameters: {
505+
source,
506+
target: ctx.target,
507+
message: ctx.body,
508+
},
509509
},
510-
});
510+
);
511511
if (!result?.success) {
512512
return buildDispatchFailure({
513513
channel: ctx.channel,

plugins/app-lifeops/src/actions/inbox.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@ import type {
1010
State,
1111
UUID,
1212
} from "@elizaos/core";
13-
import {
14-
logger,
15-
ModelType,
16-
parseToonKeyValue,
17-
} from "@elizaos/core";
13+
import { logger, ModelType, parseToonKeyValue } from "@elizaos/core";
1814
import { getRecentMessagesData } from "@elizaos/shared";
1915
import { loadInboxTriageConfig } from "../inbox/config.js";
2016
import { fetchAllMessages } from "../inbox/message-fetcher.js";
@@ -113,6 +109,16 @@ function formatInboxDraftContext(draft: DeferredInboxDraft | null): string {
113109
].join("\n");
114110
}
115111

112+
async function runInboxTextModel(
113+
runtime: IAgentRuntime,
114+
prompt: string,
115+
): Promise<string> {
116+
// Keep inbox planning/generation on runtime.useModel so core trajectory
117+
// capture records the call site; do not call provider SDKs directly here.
118+
const result = await runtime.useModel(ModelType.TEXT_SMALL, { prompt });
119+
return typeof result === "string" ? result : "";
120+
}
121+
116122
function buildInboxPolicyAcknowledgement(
117123
userText: string,
118124
): ActionResult | null {
@@ -264,10 +270,8 @@ async function resolveSubactionPlan(
264270
].join("\n");
265271

266272
try {
267-
const result = await runtime.useModel(ModelType.TEXT_SMALL, { prompt });
268-
const raw = typeof result === "string" ? result : "";
269-
const parsed =
270-
parseToonKeyValue<Record<string, unknown>>(raw);
273+
const raw = await runInboxTextModel(runtime, prompt);
274+
const parsed = parseToonKeyValue<Record<string, unknown>>(raw);
271275
if (!parsed) {
272276
return {
273277
subaction: null,
@@ -1413,8 +1417,7 @@ async function draftResponse(
14131417
.join("\n");
14141418

14151419
try {
1416-
const result = await runtime.useModel(ModelType.TEXT_SMALL, { prompt });
1417-
const text = typeof result === "string" ? result.trim() : "";
1420+
const text = (await runInboxTextModel(runtime, prompt)).trim();
14181421
return (
14191422
text || seed || "Thanks for reaching out. I'll get back to you soon."
14201423
);

0 commit comments

Comments
 (0)