Three hosts drive this runtime and each wrote its own loop: the server's
`executeSync`, the browser's `streamingExecutor`, and the package example. A
fourth is coming for device-hosted runs. They have drifted.
The server breaks explicitly on `interrupted`, on a parked status, and on
`shouldContinueExecution` — a private method that is the only complete
statement of the rules, covering cost limits and a missing next context. The
browser loops on `status !== 'done' && status !== 'error'` and escapes a
parked run only because its steps happen to return no next context. The two
agree today by coincidence, not by design: whoever changes what a parked step
returns will make the browser take another turn on a parked state.
`runAgentLoop` owns exactly two things — when to stop, and what context the
next step receives. It takes the step as a parameter rather than calling
`runtime.step` itself, because a step means very different things per host: on
the server it claims a distributed lock, persists state, dispatches hooks and
records a trace; in the browser and on a device it is a direct `runtime.step`.
Collapsing those is how a shared loop becomes something every host works
around, so persistence, hooks, streaming and quota deliberately stay outside.
The stop reason is the part worth having. Every host re-derived it after the
fact — the server to decide whether to emit `max_steps` completion signals,
the browser to choose between a terminal lifecycle event and the parked one.
Computed once, it cannot drift.
Migrating the example surfaced a real distinction: "no next context" describes
what a step PRODUCED, so it cannot be asked before the first step. A run may
legitimately open with no context, and checking it up front would end every
loop before it began. Hence `resolveTerminalReason` (status and cost, safe
before any step) alongside the full `resolveStopReason`.
No host is migrated here. The server's per-step distributed path — where
`executeStep` is scheduled and re-entered rather than looped — is NOT a loop
and must not adopt this; only its `executeSync` should, and separately, so a
regression is attributable.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* ✨ feat(desktop): implement subscription pages embedding with webview
- Add SubscriptionIframeWrapper component for embedding subscription pages in Electron webview
- Replace compile-time ENABLE_BUSINESS_FEATURES with runtime serverConfigSelectors
- Add useIsCloudActive hook to detect cloud sync status
- Add setupSubscriptionWebviewSession service for webview session management
Resolves LOBE-4589
* ✨ feat: enhance SubscriptionIframeWrapper for improved configuration
- Updated iframe URL to use OFFICIAL_URL for better maintainability.
- Integrated server configuration to conditionally enable business features.
- Cleaned up code by removing commented-out lines and unnecessary eslint suppressions.
This update improves the flexibility and readability of the SubscriptionIframeWrapper component.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: enhance link interception in SubscriptionIframeWrapper
- Updated the script to intercept both link clicks and window.open calls for better URL handling.
- Added functionality to resolve relative URLs to absolute before logging.
This improvement enhances the tracking of external link interactions within the iframe.
Signed-off-by: Innei <tukon479@gmail.com>
* 🔧 chore: clean up useIsCloudActive hook
- Removed unnecessary eslint suppressions related to react-hooks rules.
- Improved code readability by eliminating commented-out lines.
This update enhances the clarity and maintainability of the useIsCloudActive hook.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
* v2 init
* chore: update eslint suppressions and package dependencies
- Removed several eslint suppressions related to array sorting and reversing from eslint-suppressions.json to clean up the configuration.
- Updated @lobehub/lint package version from 2.0.0-beta.6 to 2.0.0-beta.7 in package.json for improvements and bug fixes.
- Made minor formatting adjustments in vitest.config.mts and various SKILL.md files for better readability and consistency.
Signed-off-by: Innei <tukon479@gmail.com>
* fix: clean up import statements and formatting
- Removed unnecessary whitespace in replaceComponentImports.ts for improved readability.
- Standardized import statements in contextEngineering.ts and createAgentExecutors.ts by adding missing spaces for consistency.
Signed-off-by: Innei <tukon479@gmail.com>
* chore: update eslint suppressions and clean up code formatting
* 🐛 fix: use vi.hoisted for mock variable initialization
Fix TDZ error in persona service test by using vi.hoisted() to ensure
mock variables are available when vi.mock factory runs.
---------
Signed-off-by: Innei <tukon479@gmail.com>