Skip to content

ElizaOS 2.0 alpha→beta migration + refactor#1

Merged
SYMBaiEX merged 15 commits into
pre-eliza-2.0-betafrom
migrate/eliza-2.0-beta
Jun 18, 2026
Merged

ElizaOS 2.0 alpha→beta migration + refactor#1
SYMBaiEX merged 15 commits into
pre-eliza-2.0-betafrom
migrate/eliza-2.0-beta

Conversation

@SYMBaiEX

Copy link
Copy Markdown
Owner

Summary

Migrates the Doolittle stack from the ElizaOS 2.0 alpha channel to the actively-managed beta channel, fixes every resulting breaking change, applies a verified refactor pass, and stops tracking generated docs/.

Migration (alpha → beta)

  • @elizaos/* alpha.5xx → beta (core beta.1, agent beta.2, skills beta.1, elizaos beta.5, plugins beta.1). @elizaos/autonomous has no beta → kept on alpha.85 with overrides forcing a single beta core (verified: no dual-core split).
  • Fixed 36 breaking-change type errors: moved subpaths (cloud/*, services/coding-agent-context@elizaos/autonomous; trajectory types → @elizaos/core), removed deleted ModelType.OBJECT_*, rewrote the Evaluator to the beta shouldRun/schema/prompt/parse/processors contract, and handled params.prompt becoming optional.
  • Patched @elizaos/[email protected]'s broken bun export condition (committed patches/ entry).

Refactor

  • Removed dead code: cli/splash.ts, empty bootstrap-runtime/, no-op import type {}, unused cron-parser.
  • Fixed packages/contracts + plugin-elizacloud dependency manifests.
  • Added a messages-aware resolveModelPromptText() across the model providers (devin/codex/claude-code/elizacloud/doolittle-plugin) to replace params.prompt ?? "" band-aids that would silently send empty content on beta's messages-only path. Added unit tests.

Housekeeping

  • Stopped tracking docs/ (now gitignored); files retained on disk.

Verification

typecheck 0 errors · 1446 tests pass · build OK · lint clean · runtime boots (doolittle status ran 28 SQL migrations, services started).


⚠️ Base note: the local line shares no common ancestor with origin/main (unrelated histories — main is a separate alpha.85 "split services" line), so GitHub will not open a PR against main. This PR is therefore based on pre-eliza-2.0-beta — a snapshot of the local line immediately before this session's work — so the diff shows exactly the migration + refactor + docs changes for review. Promoting this to main is a separate decision (it would require a force-replace of origin/main).

SYMBaiEX added 4 commits June 6, 2026 17:23
Bump @elizaos/* from alpha.5xx to the actively-managed beta channel (core beta.1, agent beta.2, skills beta.1, elizaos beta.5, plugins beta.1); keep autonomous on alpha.85 with overrides forcing a single beta core. Fix beta breaking changes: cloud/* + coding-agent-context imports -> @elizaos/autonomous, trajectory types -> @elizaos/core, ModelType.OBJECT_* removal, Evaluator rewritten to the beta shouldRun/schema/prompt/parse/processors contract. Patch [email protected] broken bun export condition. Refactor: remove dead splash.ts/bootstrap-runtime/no-op imports/cron-parser, fix contracts + plugin-elizacloud manifests, add messages-aware resolveModelPromptText() across providers (+tests). Includes pre-existing terminal-action/execution-contract work. Gates: typecheck 0, 1446 tests pass, build + lint clean.
Copilot AI review requested due to automatic review settings June 17, 2026 19:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4235adc5-63c6-409f-9fcb-fed320736c30

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch migrate/eliza-2.0-beta

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request upgrades the workspace to the ElizaOS 2.0 beta line, updating package dependencies, refactoring imports, and adapting the memory nudge evaluator to the new beta contract. It also introduces a helper to resolve prompt text when the legacy prompt parameter is absent and refines terminal intent detection. The review feedback identifies three critical issues: a regex pattern in terminal intent detection that causes false positives on common words like 'go' and 'make', a missing check in resolveModelPromptText for message content objects containing a text property, and a potential runtime crash in the memory nudge processor due to a missing null check on parsed output.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +20 to +21
const SHELL_TOOL_PATTERN =
/\b(?:bunx|bun(?:\s+(?:add|install|i|run|x|create|init))?|npx|npm(?:\s+(?:install|i|run|create|init|ci|test|exec))?|pnpm(?:\s+(?:dlx|add|install|i|run|create|exec))?|yarn(?:\s+(?:add|install|create|dlx|run))?|deno(?:\s+(?:run|task|install))?|tsx|ts-node|node(?:\s+\S+)?|cargo(?:\s+(?:new|init|run|build|test|add|install))?|rustup|go(?:\s+(?:build|run|test|get|mod|install))?|pip(?:3)?(?:\s+install)?|poetry|uv(?:\s+(?:pip|venv|run))?|make|cmake|ninja|gradle|gradlew|mvn|docker|docker-compose|podman|kubectl|helm|terraform|ansible|git(?:\s+(?:clone|init|add|commit|push|pull|fetch|status|log|diff|checkout|switch|branch|stash|merge|rebase|reset|tag))?|gh\s+\S+|create-(?:react-app|next-app|vite|tauri-app|t3-app|expo-app|nuxt-app|svelte-app|astro)|vite|next|nuxt|astro|expo|sveltekit|hardhat|forge|anchor|solana(?:\s+\S+)?|spl-token|metaplex|firebase|supabase|vercel|netlify|wrangler|playwright|cypress|vitest|jest|mocha|rg|fd|fzf|jq|curl|wget|sh|bash|zsh|fish|pwsh)\b/iu;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The SHELL_TOOL_PATTERN regex matches common English words like go and make because their subcommands are optional (?). For example, go(?:\s+(?:build|run|test|get|mod|install))? matches the word "go" on its own. This will cause isTerminalIntent to return true for completely conversational sentences like "Let's go" or "I make a cake", leading to false positives in terminal intent classification. Consider making the subcommands mandatory for common verbs like go to prevent false positives.

Suggested change
const SHELL_TOOL_PATTERN =
/\b(?:bunx|bun(?:\s+(?:add|install|i|run|x|create|init))?|npx|npm(?:\s+(?:install|i|run|create|init|ci|test|exec))?|pnpm(?:\s+(?:dlx|add|install|i|run|create|exec))?|yarn(?:\s+(?:add|install|create|dlx|run))?|deno(?:\s+(?:run|task|install))?|tsx|ts-node|node(?:\s+\S+)?|cargo(?:\s+(?:new|init|run|build|test|add|install))?|rustup|go(?:\s+(?:build|run|test|get|mod|install))?|pip(?:3)?(?:\s+install)?|poetry|uv(?:\s+(?:pip|venv|run))?|make|cmake|ninja|gradle|gradlew|mvn|docker|docker-compose|podman|kubectl|helm|terraform|ansible|git(?:\s+(?:clone|init|add|commit|push|pull|fetch|status|log|diff|checkout|switch|branch|stash|merge|rebase|reset|tag))?|gh\s+\S+|create-(?:react-app|next-app|vite|tauri-app|t3-app|expo-app|nuxt-app|svelte-app|astro)|vite|next|nuxt|astro|expo|sveltekit|hardhat|forge|anchor|solana(?:\s+\S+)?|spl-token|metaplex|firebase|supabase|vercel|netlify|wrangler|playwright|cypress|vitest|jest|mocha|rg|fd|fzf|jq|curl|wget|sh|bash|zsh|fish|pwsh)\b/iu;
const SHELL_TOOL_PATTERN =
/\b(?:bunx|bun(?:\s+(?:add|install|i|run|x|create|init))?|npx|npm(?:\s+(?:install|i|run|create|init|ci|test|exec))?|pnpm(?:\s+(?:dlx|add|install|i|run|create|exec))?|yarn(?:\s+(?:add|install|create|dlx|run))?|deno(?:\s+(?:run|task|install))?|tsx|ts-node|node(?:\s+\S+)?|cargo(?:\s+(?:new|init|run|build|test|add|install))?|rustup|go\s+(?:build|run|test|get|mod|install)|pip(?:3)?(?:\s+install)?|poetry|uv(?:\s+(?:pip|venv|run))?|make|cmake|ninja|gradle|gradlew|mvn|docker|docker-compose|podman|kubectl|helm|terraform|ansible|git(?:\s+(?:clone|init|add|commit|push|pull|fetch|status|log|diff|checkout|switch|branch|stash|merge|rebase|reset|tag))?|gh\s+\S+|create-(?:react-app|next-app|vite|tauri-app|t3-app|expo-app|nuxt-app|svelte-app|astro)|vite|next|nuxt|astro|expo|sveltekit|hardhat|forge|anchor|solana(?:\s+\S+)?|spl-token|metaplex|firebase|supabase|vercel|netlify|wrangler|playwright|cypress|vitest|jest|mocha|rg|fd|fzf|jq|curl|wget|sh|bash|zsh|fish|pwsh)\b/iu;

Comment on lines +12 to +31
export function resolveModelPromptText(params: GenerateTextParams): string {
if (typeof params.prompt === "string" && params.prompt.trim().length > 0) {
return params.prompt;
}
return (params.messages ?? [])
.map((message) => {
const { content } = message;
if (typeof content === "string") {
return content;
}
if (Array.isArray(content)) {
return content
.map((part) => (part.type === "text" ? part.text : ""))
.join("");
}
return "";
})
.filter((entry) => entry.trim().length > 0)
.join("\n");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

resolveModelPromptText does not handle the case where a message's content is an object containing a text property (e.g., { text: "hello" }), which is the standard format for message content in ElizaOS. If content is such an object, it will fall through both typeof content === "string" and Array.isArray(content) checks, returning an empty string and causing the prompt to be empty. Adding a check for content.text resolves this.

export function resolveModelPromptText(params: GenerateTextParams): string {
  if (typeof params.prompt === "string" && params.prompt.trim().length > 0) {
    return params.prompt;
  }
  return (params.messages ?? [])
    .map((message) => {
      const { content } = message;
      if (typeof content === "string") {
        return content;
      }
      if (Array.isArray(content)) {
        return content
          .map((part) => (part.type === "text" ? part.text : ""))
          .join("");
      }
      if (content && typeof content === "object" && "text" in content) {
        return (content as { text: string }).text;
      }
      return "";
    })
    .filter((entry) => entry.trim().length > 0)
    .join("\n");
}

Comment on lines +100 to +104
process: async ({
output,
}: EvaluatorProcessorContext<MemoryNudgeOutput>) => {
if (!output.shouldStore || !output.fact) {
return undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In the persist-memory-nudge processor, output is accessed directly (output.shouldStore and output.fact) without checking if output itself is null or undefined. If the model's output fails to parse or is empty, output can be null/undefined, leading to a runtime crash. Adding a defensive null check is recommended.

Suggested change
process: async ({
output,
}: EvaluatorProcessorContext<MemoryNudgeOutput>) => {
if (!output.shouldStore || !output.fact) {
return undefined;
process: async ({
output,
}: EvaluatorProcessorContext<MemoryNudgeOutput>) => {
if (!output || !output.shouldStore || !output.fact) {
return undefined;
}

SYMBaiEX added 11 commits June 17, 2026 14:33
Beta-validated audit of the alpha-era maximization plan (17 items) found Doolittle already uses the SDK near-fully: reasoning models, the 4 advanced-memory/reflection evaluators + advanced-memory plugin, AwarenessRegistry assembly, Experience/Approval/ToolPolicy/AgentEvent/Heartbeat/Trajectory services, and registry/skill/MCP marketplace clients are all already wired. The one genuine gate-safe gap: the AwarenessRegistry was assembled (5 contributors) but its composeSummary output was never injected into a turn (only called in a test). Add DOOLITTLE_SELF_AWARENESS_PROVIDER (position 100, fault-tolerant) to surface the self-awareness summary to the model, wired into doolittle-plugin assembly. +4 unit tests. Gates: typecheck 0, 1450 tests pass, build + lint clean.
Wire the ElizaOS deep-research model (ModelType.RESEARCH / o3-deep-research) as a first-class DOOLITTLE_RESEARCH action: /research <question> runs the model with web_search and returns a cited report (de-duped sources). Availability-gated via runtime.getModel(ModelType.RESEARCH) so it is inert (clear message) without OPENAI_API_KEY — boot and the suite stay green with no live key. Fault-tolerant on model errors. +5 unit tests (mocked useModel, no live call). Gates: typecheck 0, 1454 tests pass, build + lint clean.
Wire the remaining ElizaOS SDK runtime capabilities additively (no existing system removed), via a guarded plugin init (packages/plugins/doolittle-plugin/sdk-capabilities.ts): (1) HOOK_TOOL_AFTER tool-audit observability; (2) the autonomous trigger dispatch worker (registerTriggerTaskWorker, gated by triggersFeatureEnabled); (3) a recurring SDK TaskWorker (DOOLITTLE_SELF_MAINTENANCE, idempotent via fixed id) that refreshes the self-awareness summary cache. Plus explicit per-ModelType sampling settings (MODEL_SETTINGS) in the character (low temp for reasoning determinism). Each step independently fault-guarded so startup is never blocked. Gates: typecheck 0, 1457 tests pass, build + lint clean, agent boots clean with all wiring registered (no guard failures).
The ElizaOS SDK already caches its action/evaluator/planner path (renderContextObject -> promptSegments -> provider cache plan). The gap was Doolittle's OWN direct useModel calls (the chat-turn shortcut fast paths), which sent raw prompt strings with no caching on any provider.

Add a shared, provider-aware prompt-cache module (packages/agent/src/runtime/prompt-cache): buildCacheablePrompt() segments a prompt into a cache-stable prefix + volatile suffix and emits SDK promptSegments (+ providerOptions) losslessly (prompt === segments.join('')). Provider policy: explicit (anthropic cache_control, openai promptCacheKey), implicit (ollama prefix-KV), none (custom CLI plugins). Deterministic, versioned cache keys (sha256 of templateVersion+versionDigest+provider+model+stableContent) that rotate on character/persona/tool/model change; volatile content never keyed. promptCacheMetrics observability recorder + snapshot. README with design, extension, and limitations.

Integration: refactor buildDirectInformationalPrompt into a lossless stable/volatile split; route all 3 shortcut handlers (direct-informational + 2 profile-memory paths) through buildShortcutPromptCache (single funnel, never per-agent). +22 module tests. Gates: typecheck 0, 1479 tests pass, build + lint clean, boots clean.
Release-review findings (gate-safe): (1) AGENTS.md was a stale <claude-mem-context> memory dump that ContextFilesService injects into the LIVE model prompt every non-minimal turn (correctness bug + wasted tokens) — replaced with concise, current agent/operator guidance, plus a regression test asserting no memory-dump marker. (2) README 'Versioning' section and packages/plugins/plugin-sql/README.md still claimed the ElizaOS 'alpha' line — updated to 2.0.0-beta with the plugin-sql bun-export patch noted. Gates: typecheck 0, docs-truth passes, lint clean.
…e metrics

From the 16-workstream release review (gate-safe fixes): (1) /mcp call and /acp call no longer throw uncaught SyntaxError on malformed JSON — parseNamedToolPayload guards JSON.parse and returns undefined so callers render a usage message. (2) /cron pause|resume|run|remove <bad-id> no longer crashes the turn — the cron dispatch is wrapped so not-found errors surface as a clean failure message. (3) Prompt-cache: removed the dead/buggy capStableBlocks max<=0 branch; added an integration test asserting promptSegments reach useModel losslessly per provider at the real funnel (buildShortcutPromptCache). (4) Observability: surfaced promptCacheMetrics in /status (calls/eligible/segmented + hit-rate when usage is available). Gates: typecheck 0, 1483 tests pass, build + lint clean.
Reliability (one failure no longer cascades): (1) deferred plugin hydration isolates each plugin in try/catch and still marks runtime ready — a single optional plugin failure no longer aborts the batch nor permanently poisons the memoized hydration promise; (2) cron tick isolates each job — a throwing executor is recorded and the job backs off to its normal cadence instead of aborting the tick and hot-looping; (3) runPostCommandTurn now finishes the run on any thrown exception (finishTurn 'error', guarded by getActive so an inner path that already finalized is never double-finished) — runs no longer strand in 'thinking'.

Performance (hot paths): (4) SettingsService.get() gains an mtime-keyed read-through cache (was readFileSync+JSON.parse+normalize on every call, 4+/turn), returning clones so callers can't corrupt the cache; (5) SOUL.md read is memoized by path+mtime (was re-read + stripped every turn), keeping the directory walk live so new/deleted files are still detected.

Gates: typecheck 0, 1483 tests pass, build + lint clean.
(1) runGatewayWatchdogPlatform now contains any per-platform failure (e.g. a throwing adapter.health()/watch()) and returns a 'recover' supervision outcome instead of throwing — one bad adapter no longer aborts the watchdog loop for all other platforms. (2) /commands browse renders the full catalog instead of silently truncating at 80 (the catalog has ~101 entries); the limit now only bounds ranked search results. Gates: typecheck 0, 1483 tests pass, build + lint clean.
…pback

The HTTP API bound to 0.0.0.0 by default with no authentication, exposing /secrets/get values, chat-driven execution, and impersonation on every interface. Make it local-first: DOOLITTLE_HOST now defaults to 127.0.0.1 (OS-restricted to this machine), and a new server auth gate (server/auth.ts) allows loopback binds while REQUIRING a bearer token (DOOLITTLE_API_TOKEN) for any non-loopback bind — without a token, a non-loopback bind rejects every request (fail-safe), so the API is never silently exposed. .env.example updated to the safe default + token guidance. +5 auth unit tests. Gates: typecheck 0, 1488 tests pass, build + lint clean.
Prepare for open-source release: add MIT LICENSE (+ root license field), SECURITY.md (private reporting + the local-first security model), CONTRIBUTING.md (gates + action/provider extension recipes), and CHANGELOG.md (beta migration + this release). Re-track docs/ (un-ignored) so the ~8 README-linked reference docs resolve on a fresh clone and the doc-truth acceptance gate passes from a clean checkout. Gates: check:acceptance passes (repo-hygiene + plugin-boundaries + doc-truth), typecheck 0, lint clean.
… fallback

A Ctrl-C/abort surfaces as a runFailureMessage, which satisfied the direct-local fallback gate and re-ran the exact work the user just cancelled. resolvePostProviderFallback now short-circuits to a continue-state (without consulting the fallback loader) when options.abortSignal is aborted. +2 regression tests. Gates: typecheck 0, 1490 tests pass, build + lint + acceptance all green.
@SYMBaiEX SYMBaiEX merged commit 496a562 into pre-eliza-2.0-beta Jun 18, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants