Skip to content

Commit cbfa278

Browse files
author
Shaw
committed
update embeds
1 parent 8edaffe commit cbfa278

17 files changed

Lines changed: 827 additions & 548 deletions

File tree

packages/app-core/src/runtime/eliza.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,22 @@ interface RuntimeHookModule {
425425

426426
const TRAINING_RUNTIME_HOOKS_SPECIFIER = "@elizaos/plugin-training";
427427

428+
/**
429+
* Returns true only for genuine "module is not installed" import failures.
430+
* Bun raises `ResolveMessage` with `code === "ERR_MODULE_NOT_FOUND"` when a
431+
* specifier cannot be resolved; Node uses the same `code`. Anything else
432+
* (syntax error, runtime error during module init, tsconfig path hijack,
433+
* missing transitive dependency) is a real load failure and must NOT be
434+
* misreported as "not installed".
435+
*/
436+
function isModuleNotFoundError(err: unknown): boolean {
437+
if (!err || typeof err !== "object") return false;
438+
const errObj = err as { code?: unknown; constructor?: { name?: string } };
439+
if (errObj.code === "ERR_MODULE_NOT_FOUND") return true;
440+
if (errObj.constructor?.name === "ResolveMessage") return true;
441+
return false;
442+
}
443+
428444
async function registerTrainingRuntimeHooks(
429445
runtime: AgentRuntime,
430446
): Promise<void> {
@@ -434,10 +450,18 @@ async function registerTrainingRuntimeHooks(
434450
TRAINING_RUNTIME_HOOKS_SPECIFIER
435451
)) as RuntimeHookModule;
436452
} catch (err) {
437-
logger.warn(
438-
`[eliza] @elizaos/plugin-training not installed, skipping runtime hooks: ${formatError(err)}`,
453+
if (isModuleNotFoundError(err)) {
454+
logger.warn(
455+
`[eliza] @elizaos/plugin-training not installed, skipping runtime hooks`,
456+
);
457+
return;
458+
}
459+
// Real load failure (syntax error, broken transitive, init throw, etc.) —
460+
// surface it loudly so it is not mistaken for "not installed".
461+
logger.error(
462+
`[eliza] @elizaos/plugin-training failed to load (not 'not installed'): ${formatErrorWithStack(err)}`,
439463
);
440-
return;
464+
throw err;
441465
}
442466

443467
if (!hookMod.registerTrainingRuntimeHooks) {

packages/cloud-frontend/vite.config.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,18 @@ export default defineConfig(({ mode }) => {
410410
// Keep the build warning budget explicit so import and resolver warnings
411411
// still stand out in CI output.
412412
chunkSizeWarningLimit: 3000,
413+
// Strip route-specific vendor chunks (wallet, docs, charts) from the
414+
// entry's <link rel="modulepreload"> set. Rolldown otherwise lists every
415+
// transitive dep of every lazy route in the entry's preload manifest,
416+
// which on the landing page was 58 preloads (22 of them wallet chunks)
417+
// before the user navigated anywhere. Those chunks still load on demand
418+
// via Vite's __vitePreload helper at the dynamic-import callsite, so
419+
// dropping them from the entry only saves the initial connection budget.
420+
modulePreload: {
421+
polyfill: false,
422+
resolveDependencies: (_filename, deps) =>
423+
deps.filter((dep) => !/vendor-(wallet|docs|charts)-/.test(dep)),
424+
},
413425
rolldownOptions: {
414426
output: {
415427
codeSplitting: {

packages/core/src/runtime/planner-loop.ts

Lines changed: 84 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ export async function runPlannerLoop(
131131
const failures: FailureLike[] = [];
132132
let terminalOnlyContinuations = 0;
133133
let requiredToolMisses = 0;
134+
let unavailableToolCallRetries = 0;
135+
let silentFailedFinishRecoveries = 0;
134136
const requireNonTerminalToolCall =
135137
params.requireNonTerminalToolCall === true &&
136138
hasExposedNonTerminalTool(params.tools);
@@ -218,27 +220,19 @@ export async function runPlannerLoop(
218220
!hasExecutedNonTerminalTool(trajectory)
219221
) {
220222
requiredToolMisses++;
221-
if (requiredToolMisses > config.maxRequiredToolMisses) {
222-
params.runtime.logger?.warn?.(
223-
{
224-
src: "planner-loop",
225-
iteration,
226-
misses: requiredToolMisses,
227-
max: config.maxRequiredToolMisses,
228-
messageToUser: plannerOutput.messageToUser,
229-
},
230-
"required_tool_misses budget exhausted; honoring planner's terminal reply instead of throwing",
231-
);
232-
} else {
233-
handleRequiredToolPlannerMiss({
234-
trajectory,
235-
iteration,
236-
plannerOutput,
237-
reason: "no_tool_calls",
238-
logger: params.runtime.logger,
239-
});
240-
continue;
241-
}
223+
assertTrajectoryLimit({
224+
kind: "required_tool_misses",
225+
max: config.maxRequiredToolMisses,
226+
observed: requiredToolMisses,
227+
});
228+
handleRequiredToolPlannerMiss({
229+
trajectory,
230+
iteration,
231+
plannerOutput,
232+
reason: "no_tool_calls",
233+
logger: params.runtime.logger,
234+
});
235+
continue;
242236
}
243237
trajectory.steps.push({
244238
iteration,
@@ -326,27 +320,19 @@ export async function runPlannerLoop(
326320
!hasExecutedNonTerminalTool(trajectory)
327321
) {
328322
requiredToolMisses++;
329-
if (requiredToolMisses > config.maxRequiredToolMisses) {
330-
params.runtime.logger?.warn?.(
331-
{
332-
src: "planner-loop",
333-
iteration,
334-
misses: requiredToolMisses,
335-
max: config.maxRequiredToolMisses,
336-
messageToUser: plannerOutput.messageToUser,
337-
},
338-
"required_tool_misses budget exhausted; honoring planner's terminal tool-call reply instead of throwing",
339-
);
340-
} else {
341-
handleRequiredToolPlannerMiss({
342-
trajectory,
343-
iteration,
344-
plannerOutput,
345-
reason: "terminal_only_tool_calls",
346-
logger: params.runtime.logger,
347-
});
348-
continue;
349-
}
323+
assertTrajectoryLimit({
324+
kind: "required_tool_misses",
325+
max: config.maxRequiredToolMisses,
326+
observed: requiredToolMisses,
327+
});
328+
handleRequiredToolPlannerMiss({
329+
trajectory,
330+
iteration,
331+
plannerOutput,
332+
reason: "terminal_only_tool_calls",
333+
logger: params.runtime.logger,
334+
});
335+
continue;
350336
}
351337
const finalMessage = terminalMessageFromToolCalls(
352338
plannerOutput.toolCalls,
@@ -388,12 +374,43 @@ export async function runPlannerLoop(
388374
const nonTerminalCalls = plannerOutput.toolCalls
389375
.filter((toolCall) => !isTerminalToolCall(toolCall))
390376
.map((toolCall, index) => ensureToolCallId(toolCall, iteration, index));
391-
trajectory.plannedQueue.push(...nonTerminalCalls);
377+
const unavailable = splitUnavailableToolCalls(
378+
nonTerminalCalls,
379+
params.tools,
380+
);
381+
if (unavailable.invalid.length > 0) {
382+
params.runtime.logger?.warn?.(
383+
{
384+
iteration,
385+
invalidToolCalls: unavailable.invalid.map(
386+
(toolCall) => toolCall.name,
387+
),
388+
},
389+
"Planner called unavailable tools; retrying without executing them",
390+
);
391+
trajectory.context = appendUnavailableToolCallEvent({
392+
context: trajectory.context,
393+
iteration,
394+
invalidToolCalls: unavailable.invalid,
395+
tools: params.tools,
396+
});
397+
if (unavailable.valid.length === 0) {
398+
unavailableToolCallRetries++;
399+
assertTrajectoryLimit({
400+
kind: "unavailable_tool_calls",
401+
max: config.maxUnavailableToolCallRetries,
402+
observed: unavailableToolCallRetries,
403+
});
404+
continue;
405+
}
406+
}
407+
const validNonTerminalCalls = unavailable.valid;
408+
trajectory.plannedQueue.push(...validNonTerminalCalls);
392409
trajectory.context = {
393410
...trajectory.context,
394411
plannedQueue: [
395412
...(trajectory.context.plannedQueue ?? []),
396-
...nonTerminalCalls.map((toolCall) => ({
413+
...validNonTerminalCalls.map((toolCall) => ({
397414
id: toolCall.id,
398415
name: toolCall.name,
399416
args: stringifyForModel(toolCall.params ?? {}),
@@ -402,7 +419,7 @@ export async function runPlannerLoop(
402419
})),
403420
],
404421
};
405-
for (const toolCall of nonTerminalCalls) {
422+
for (const toolCall of validNonTerminalCalls) {
406423
trajectory.context = appendContextEvent(trajectory.context, {
407424
id: `queue:${toolCall.id ?? toolCall.name}:${iteration}`,
408425
type: "planned_tool_call",
@@ -503,12 +520,32 @@ export async function runPlannerLoop(
503520
appendEvaluatorContextEvent(trajectory, evaluator, iteration);
504521

505522
if (evaluator.decision === "FINISH") {
523+
if (
524+
shouldRecoverSilentFailedFinish({
525+
evaluator,
526+
trajectory,
527+
recoveryCount: silentFailedFinishRecoveries,
528+
})
529+
) {
530+
silentFailedFinishRecoveries++;
531+
trajectory.context = appendSilentFailedFinishRecoveryEvent({
532+
context: trajectory.context,
533+
iteration,
534+
evaluator,
535+
trajectory,
536+
});
537+
continue;
538+
}
506539
return {
507540
status: "finished",
508541
trajectory,
509542
evaluator,
510543
finalMessage: userSafeFinalMessage(
511-
evaluator.messageToUser ?? latestToolResultText(trajectory),
544+
evaluator.messageToUser ??
545+
latestToolResultText(trajectory) ??
546+
(evaluator.success === false
547+
? failedToolFallbackMessage(trajectory)
548+
: undefined),
512549
trajectory,
513550
),
514551
};
@@ -1636,6 +1673,7 @@ async function executeQueuedToolCall(params: {
16361673
toolName: params.toolCall.name,
16371674
success: result.success,
16381675
error: result.error,
1676+
repeatKey: toolFailureRepeatKey(params.toolCall),
16391677
};
16401678
if (!result.success || result.error != null) {
16411679
params.failures.push(failure);
19.7 KB
Loading
23.5 KB
Loading
29.1 KB
Loading

packages/homepage/src/App.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { BRAND_COLORS } from "@elizaos/shared-brand";
2+
import { Loader2 } from "lucide-react";
23
import { lazy, Suspense } from "react";
34
import { BrowserRouter, Route, Routes } from "react-router-dom";
45
import { QueryProvider } from "@/components/providers/query-provider";
@@ -15,12 +16,12 @@ function RouteFallback() {
1516
<main
1617
className="theme-app min-h-screen flex flex-col items-center justify-center px-4"
1718
style={{
18-
background: BRAND_COLORS.black,
19-
color: BRAND_COLORS.white,
19+
background: BRAND_COLORS.orange,
20+
color: BRAND_COLORS.black,
2021
fontFamily: "Poppins",
2122
}}
2223
>
23-
<div className="opacity-70">Loading…</div>
24+
<Loader2 className="h-8 w-8 animate-spin opacity-80" />
2425
</main>
2526
);
2627
}

packages/homepage/src/pages/get-started.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,19 @@ import {
88
} from "@elizaos/ui/cloud-ui";
99
import { animated, useSpring, useTrail } from "@react-spring/web";
1010
import { ArrowLeft, Check, Copy, ExternalLink, Info, Send } from "lucide-react";
11-
import { useCallback, useEffect, useRef, useState } from "react";
11+
import { lazy, Suspense, useCallback, useEffect, useRef, useState } from "react";
1212
import { Link, useNavigate, useSearchParams } from "react-router-dom";
1313
import { ElizaLogo } from "@/components/brand/eliza-logo";
1414
import {
1515
buildFullPhoneNumber,
1616
PhoneNumberInput,
1717
useCountryOptions,
1818
} from "@/components/login/phone-number-input";
19-
import ShaderBackground from "@/components/ShaderBackground/ShaderBackground";
19+
20+
// Defer the WebGL shader background so the form UI is interactive immediately.
21+
const ShaderBackground = lazy(
22+
() => import("@/components/ShaderBackground/ShaderBackground"),
23+
);
2024
import {
2125
buildElizaSmsHref,
2226
ELIZA_PHONE_FORMATTED,
@@ -805,7 +809,9 @@ export default function GetStartedPage() {
805809

806810
return (
807811
<main className="min-h-screen flex flex-col relative">
808-
<ShaderBackground />
812+
<Suspense fallback={null}>
813+
<ShaderBackground />
814+
</Suspense>
809815
<div
810816
className="fixed inset-0 pointer-events-none mix-blend-overlay z-0"
811817
style={{

packages/homepage/src/pages/leaderboard.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,19 @@ import type {
3131
HTMLAttributes,
3232
SVGProps,
3333
} from "react";
34-
import { useCallback, useEffect, useRef, useState } from "react";
34+
import { lazy, Suspense, useCallback, useEffect, useRef, useState } from "react";
3535
import { useNavigate } from "react-router-dom";
3636
import BlobButton from "@/components/BlobButton";
3737
import { ElizaLogo } from "@/components/brand/eliza-logo";
3838
import ModelB, { type ModelBHandle } from "@/components/ModelViewers/ModelB";
39-
import ShaderBackground from "@/components/ShaderBackground/ShaderBackground";
40-
import VideoCall from "@/components/VideoCall";
39+
40+
// Heavy WebGL bundles split out so the leaderboard route shell becomes
41+
// interactive without waiting for the shader/canvas code. ShaderBackground is
42+
// opt-in via ?shader=1. VideoCall only mounts when the user opens the modal.
43+
const ShaderBackground = lazy(
44+
() => import("@/components/ShaderBackground/ShaderBackground"),
45+
);
46+
const VideoCall = lazy(() => import("@/components/VideoCall"));
4147
import { buildElizaSmsHref } from "@/lib/contact";
4248
import type { SpringAnimatedStyle } from "@/lib/spring-types";
4349

@@ -735,7 +741,11 @@ export default function Leaderboard() {
735741
transition: "background-color 240ms ease, background 240ms ease",
736742
}}
737743
>
738-
{SHADER_BACKGROUND_OPT_IN && <ShaderBackground />}
744+
{SHADER_BACKGROUND_OPT_IN && (
745+
<Suspense fallback={null}>
746+
<ShaderBackground />
747+
</Suspense>
748+
)}
739749
<ModelB
740750
ref={modelRef}
741751
tryActive={platform === "try"}
@@ -1270,7 +1280,11 @@ export default function Leaderboard() {
12701280
)}
12711281
</p>
12721282
</AnimatedDiv>
1273-
<VideoCall visible={showVideo} onClose={() => setShowVideo(false)} />
1283+
{showVideo && (
1284+
<Suspense fallback={null}>
1285+
<VideoCall visible={showVideo} onClose={() => setShowVideo(false)} />
1286+
</Suspense>
1287+
)}
12741288
<AnimatedDiv
12751289
className={`fixed inset-0 z-50 bg-white pointer-events-none flex items-center justify-center duration-100 ${
12761290
introDone ? "opacity-0" : ""

packages/homepage/vite.config.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import fs from "node:fs";
22
import path from "node:path";
33
import tailwindcss from "@tailwindcss/vite";
44
import react from "@vitejs/plugin-react";
5+
import { visualizer } from "rollup-plugin-visualizer";
56
import { defineConfig, type Plugin } from "vite";
67

78
/**
@@ -26,9 +27,27 @@ function gh404Fallback(): Plugin {
2627
}
2728

2829
export default defineConfig({
29-
plugins: [react(), tailwindcss(), gh404Fallback()],
30+
plugins: [
31+
react(),
32+
tailwindcss(),
33+
gh404Fallback(),
34+
visualizer({
35+
filename: "dist/stats.html",
36+
gzipSize: true,
37+
brotliSize: false,
38+
template: "treemap",
39+
}),
40+
],
3041
resolve: {
31-
dedupe: ["react", "react-dom", "react-router", "react-router-dom"],
42+
dedupe: [
43+
"react",
44+
"react-dom",
45+
"react-router",
46+
"react-router-dom",
47+
"@react-three/fiber",
48+
"three",
49+
"zod",
50+
],
3251
alias: [
3352
{ find: "@", replacement: path.resolve(__dirname, "./src") },
3453
{

0 commit comments

Comments
 (0)