Merge pull request #720 from rowboatlabs/runtime-refactor

refactor(x): the runtime moves under one roof — core/src/runtime/
This commit is contained in:
Ramnique Singh 2026-07-10 16:36:04 +05:30 committed by GitHub
commit 599b7d13fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
164 changed files with 487 additions and 464 deletions

View file

@ -34,6 +34,12 @@ jobs:
- name: Run apps/x Vitest suites
run: npm test
# Typechecks with the dev tsconfigs, which include test files —
# the build tsconfigs exclude them and vitest strips types without
# checking, so this is the only gate that sees type errors in tests.
- name: Typecheck apps/x packages
run: npm run typecheck
apps-x-electron-package:
name: apps/x Electron package smoke test
runs-on: ubuntu-latest

View file

@ -139,6 +139,7 @@ Long-form docs for specific features. Read the relevant file before making chang
### Verify compilation
```bash
cd apps/x && npm run deps && npm run lint
cd apps/x && npm run typecheck # dev tsconfigs — the only gate that typechecks *.test.ts
```
## Tech Stack

View file

@ -326,7 +326,7 @@ Three branches by `trigger`:
### 5. Live Note skill (Copilot-facing)
- **Purpose**: teaches Copilot the `live:` model — operational posture (act-first), the strong/medium/anti-signal taxonomy and how to act on each, the **always-extend-not-fork** rule for already-live notes, user-facing language (call them "live notes"; surface the **Live Note panel** by name), the auto-run-once-on-create/edit default, schema, triggers, YAML-safety rules, insertion workflow, and the `run-live-note-agent` tool with `context` backfills.
- **File**: `packages/core/src/application/assistant/skills/live-note/skill.ts`. Exported `skill` constant.
- **File**: `packages/core/src/runtime/assembly/skills/live-note/skill.ts`. Exported `skill` constant.
- **Schema interpolation**: at module load, `stringifyYaml(z.toJSONSchema(LiveNoteSchema))` is interpolated into the "Canonical Schema" section. Edits to `LiveNoteSchema` propagate automatically.
- **Output**: markdown, injected into the Copilot system prompt when `loadSkill('live-note')` fires.
- **Invoked by**: Copilot's `loadSkill` builtin tool. Registration in `skills/index.ts`.
@ -334,7 +334,7 @@ Three branches by `trigger`:
### 6. Copilot trigger paragraph
- **Purpose**: tells Copilot *when* to load the `live-note` skill, and frames how aggressively to act once loaded.
- **File**: `packages/core/src/application/assistant/instructions.ts` (look for the "Live Notes" paragraph).
- **File**: `packages/core/src/runtime/assembly/copilot/instructions.ts` (look for the "Live Notes" paragraph).
- **Strong signals (load + act without asking)**: cadence words ("every morning / daily / hourly…"), living-document verbs ("keep a running summary of…", "maintain a digest of…"), watch/monitor verbs, pin-live framings ("always show the latest X here"), direct ("track / follow X"), event-conditional ("whenever a relevant email comes in…").
- **Medium signals (load + answer the one-off + offer)**: time-decaying questions ("what's the weather?", "USD/INR right now?", "service X status?"), note-anchored snapshots ("show me my schedule here"), recurring artifacts ("morning briefing", "weekly review", "Acme dashboard"), topic-following / catch-up.
- **Anti-signals (do NOT make live)**: definitional questions, one-off lookups, manual document editing.
@ -343,7 +343,7 @@ Three branches by `trigger`:
### 7. `run-live-note-agent` tool — `context` parameter description
- **Purpose**: a mini-prompt (a Zod `.describe()`) that guides Copilot on when to pass extra context for a run.
- **File**: `packages/core/src/application/lib/builtin-tools.ts` (the `run-live-note-agent` tool definition).
- **File**: `packages/core/src/runtime/tools/catalog.ts` (the `run-live-note-agent` tool definition).
- **Inputs**: `filePath` (workspace-relative; the tool strips the `knowledge/` prefix internally), optional `context`.
- **Output**: flows into `runLiveNoteAgent(..., 'manual')``buildMessage` → appended as `**Context:**` in the agent message.
- **Key use case**: backfill a newly-made-live note so its body isn't empty on day 1.
@ -394,10 +394,10 @@ Conventions:
| Deprecated Today.md one-time migration | `packages/core/src/knowledge/deprecate_today_note.ts` |
| Gmail event producer | `packages/core/src/knowledge/sync_gmail.ts` |
| Calendar event producer + digest | `packages/core/src/knowledge/sync_calendar.ts` |
| Copilot skill | `packages/core/src/application/assistant/skills/live-note/skill.ts` |
| Skill registration | `packages/core/src/application/assistant/skills/index.ts` |
| Copilot trigger paragraph | `packages/core/src/application/assistant/instructions.ts` |
| `run-live-note-agent` builtin tool | `packages/core/src/application/lib/builtin-tools.ts` |
| Copilot skill | `packages/core/src/runtime/assembly/skills/live-note/skill.ts` |
| Skill registration | `packages/core/src/runtime/assembly/skills/index.ts` |
| Copilot trigger paragraph | `packages/core/src/runtime/assembly/copilot/instructions.ts` |
| `run-live-note-agent` builtin tool | `packages/core/src/runtime/tools/catalog.ts` |
| Editor toolbar (Radio button → panel) | `apps/renderer/src/components/editor-toolbar.tsx` |
| Live Note panel (single-view editor) | `apps/renderer/src/components/live-note-sidebar.tsx` |
| Status hook (`useLiveNoteAgentStatus`) | `apps/renderer/src/hooks/use-live-note-agent-status.ts` |

View file

@ -108,7 +108,7 @@ is live) to the outgoing message as `UserImagePart`s and sets
(`data`, `mediaType`), `source: 'camera' | 'screen'`, `capturedAt`. Unlike
file attachments (path references read via the `LLMParse` tool), image
parts go to the model as real multimodal image parts.
- `packages/core/src/agents/message-encoding.ts` `convertFromMessages`:
- `packages/core/src/runtime/assembly/message-encoding.ts` `convertFromMessages`:
emits a context line (frame counts + time span), then labeled groups —
a `"Webcam frames (oldest to newest):"` text part before camera images and
a `"Screen-share frames (oldest to newest):"` text part before screen
@ -176,11 +176,11 @@ Push-to-talk is disabled while a call owns the mic.
| Prompt | Where |
|--------|-------|
| `# Video Mode (Live Camera)` system section — how to use webcam frames, coaching guidance, screen-share rules ("treat the screen as the primary subject", "last screen frame is current"), etiquette (never comment on appearance) | `packages/core/src/application/assistant/capabilities/modes.ts` (the `VIDEO_MODE` fragment of the `video-mode` capability, composed by `agents/compose-instructions.ts`) |
| `# Video Mode (Live Camera)` system section — how to use webcam frames, coaching guidance, screen-share rules ("treat the screen as the primary subject", "last screen frame is current"), etiquette (never comment on appearance) | `packages/core/src/runtime/assembly/capabilities/modes.ts` (the `VIDEO_MODE` fragment of the `video-mode` capability, composed by `agents/compose-instructions.ts`) |
| `# Practice Session (Coach Mode)` system section — coaching persona: specific/actionable feedback after each take, one-sentence interjections mid-flow, structured debrief on wrap-up | `capabilities/modes.ts` (the `COACH_MODE` fragment, directly after the video capability) |
| "Driving the app" paragraph in the video-mode section — on calls, prefer app-navigation read-view/open-item (show while telling) over describing or squinting at frames | same `# Video Mode` section; full action docs in the `app-navigation` skill (`application/assistant/skills/app-navigation/skill.ts`) |
| Per-message frame context line `[Video mode: N live webcam frames … and M frames of the user's shared screen …]` + group labels | `packages/core/src/agents/runtime.ts` (`convertFromMessages`) |
| `videoMode` / `coachMode` composition overrides (session-sticky; flips bust prefix cache) | `packages/core/src/turns/bridges/real-agent-resolver.ts` (`CompositionOverrides`); set from `App.tsx` `sendConfig` |
| "Driving the app" paragraph in the video-mode section — on calls, prefer app-navigation read-view/open-item (show while telling) over describing or squinting at frames | same `# Video Mode` section; full action docs in the `app-navigation` skill (`runtime/assembly/skills/app-navigation/skill.ts`) |
| Per-message frame context line `[Video mode: N live webcam frames … and M frames of the user's shared screen …]` + group labels | `packages/core/src/runtime/legacy/engine.ts` (`convertFromMessages`) |
| `videoMode` / `coachMode` composition overrides (session-sticky; flips bust prefix cache) | `packages/core/src/runtime/turns/bridges/real-agent-resolver.ts` (`CompositionOverrides`); set from `App.tsx` `sendConfig` |
Voice input/output prompt sections (`# Voice Input`, `# Voice Output`) are
reused untouched — calls set `voiceInput` per utterance and force

View file

@ -2,7 +2,7 @@ import { shell, BrowserWindow } from 'electron';
import { createAuthServer } from './auth-server.js';
import * as composioClient from '@x/core/dist/composio/client.js';
import { composioAccountsRepo } from '@x/core/dist/composio/repo.js';
import { invalidateCopilotInstructionsCache } from '@x/core/dist/application/assistant/instructions.js';
import { invalidateCopilotInstructionsCache } from '@x/core/dist/runtime/assembly/copilot/instructions.js';
import { CURATED_TOOLKIT_SLUGS } from '@x/shared/dist/composio.js';
import type { LocalConnectedAccount, Toolkit } from '@x/core/dist/composio/types.js';
import { triggerSync as triggerGmailSync } from '@x/core/dist/knowledge/sync_gmail.js';

View file

@ -12,8 +12,8 @@ import { watcher as watcherCore, workspace } from '@x/core';
import { WorkDir } from '@x/core/dist/config/config.js';
import { workspace as workspaceShared } from '@x/shared';
import * as mcpCore from '@x/core/dist/mcp/mcp.js';
import * as runsCore from '@x/core/dist/runs/runs.js';
import { bus } from '@x/core/dist/runs/bus.js';
import * as runsCore from '@x/core/dist/runtime/legacy/runs.js';
import { bus } from '@x/core/dist/runtime/legacy/bus.js';
import { serviceBus } from '@x/core/dist/services/service_bus.js';
import type { FSWatcher } from 'chokidar';
import fs from 'node:fs/promises';
@ -30,8 +30,8 @@ import { RunEvent } from '@x/shared/dist/runs.js';
import { ServiceEvent } from '@x/shared/dist/service-events.js';
import type { SessionBusEvent } from '@x/shared/dist/sessions.js';
import { isDurableTurnEvent } from '@x/shared/dist/turns.js';
import type { ISessions, EmitterSessionBus } from '@x/core/dist/sessions/index.js';
import type { ITurnEventBus } from '@x/core/dist/turns/event-hub.js';
import type { ISessions, EmitterSessionBus } from '@x/core/dist/runtime/sessions/index.js';
import type { ITurnEventBus } from '@x/core/dist/runtime/turns/event-hub.js';
import container from '@x/core/dist/di/container.js';
import { listOnboardingModels } from '@x/core/dist/models/models-dev.js';
import { testModelConnection, listModelsForProvider, generateOneShot } from '@x/core/dist/models/models.js';
@ -55,7 +55,7 @@ import * as codeGit from '@x/core/dist/code-mode/git/service.js';
import { readProjectDir, readProjectFile } from '@x/core/dist/code-mode/projects/fs.js';
import { ensureTerminal, writeTerminal, resizeTerminal, disposeTerminal } from './terminal.js';
import type { CodeSession } from '@x/shared/dist/code-sessions.js';
import { invalidateCopilotInstructionsCache } from '@x/core/dist/application/assistant/instructions.js';
import { invalidateCopilotInstructionsCache } from '@x/core/dist/runtime/assembly/copilot/instructions.js';
import { triggerSync as triggerGranolaSync } from '@x/core/dist/knowledge/granola/sync.js';
import { ISlackConfigRepo } from '@x/core/dist/slack/repo.js';
import { IChannelsConfigRepo } from '@x/core/dist/channels/repo.js';

View file

@ -36,7 +36,7 @@ import { init as initEventProcessor, registerConsumer } from "@x/core/dist/event
import { liveNoteEventConsumer } from "@x/core/dist/knowledge/live-note/event-consumer.js";
import { init as initBackgroundTaskScheduler } from "@x/core/dist/background-tasks/scheduler.js";
import { backgroundTaskEventConsumer } from "@x/core/dist/background-tasks/event-consumer.js";
import { startSkillsWatcher, stopSkillsWatcher } from "@x/core/dist/application/assistant/skills/watcher.js";
import { startSkillsWatcher, stopSkillsWatcher } from "@x/core/dist/runtime/assembly/skills/watcher.js";
import { init as initAppsServer, shutdown as shutdownAppsServer } from "@x/core/dist/apps/server.js";
import { registerAppsHostApi } from "@x/core/dist/apps/host-api.js";
import { setTokenCipher as setGithubTokenCipher } from "@x/core/dist/apps/github-auth.js";
@ -52,7 +52,7 @@ import { execFileSync } from "node:child_process";
import { init as initChromeSync } from "@x/core/dist/knowledge/chrome-extension/server/server.js";
import container, { registerBrowserControlService, registerNotificationService } from "@x/core/dist/di/container.js";
import type { CodeModeManager } from "@x/core/dist/code-mode/acp/manager.js";
import type { ISessions } from "@x/core/dist/sessions/index.js";
import type { ISessions } from "@x/core/dist/runtime/sessions/index.js";
import { browserViewManager, BROWSER_PARTITION } from "./browser/view.js";
import { setupBrowserEventForwarding } from "./browser/ipc.js";
import { ElectronBrowserControlService } from "./browser/control-service.js";

View file

@ -1,5 +1,5 @@
import * as runsCore from '@x/core/dist/runs/runs.js';
import { bus } from '@x/core/dist/runs/bus.js';
import * as runsCore from '@x/core/dist/runtime/legacy/runs.js';
import { bus } from '@x/core/dist/runtime/legacy/bus.js';
async function main() {
const { id } = await runsCore.createRun({

View file

@ -5,6 +5,7 @@
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"typecheck": "tsc -b",
"lint": "eslint .",
"preview": "vite preview",
"test": "vitest run",

View file

@ -16,7 +16,11 @@
"test": "npm run shared && npm run test:shared && npm run test:core && npm run test:renderer",
"test:shared": "cd packages/shared && npm test",
"test:core": "cd packages/core && npm test",
"test:renderer": "cd apps/renderer && npm test"
"test:renderer": "cd apps/renderer && npm test",
"typecheck": "npm run shared && npm run typecheck:shared && npm run typecheck:core && npm run typecheck:renderer",
"typecheck:shared": "cd packages/shared && npm run typecheck",
"typecheck:core": "cd packages/core && npm run typecheck",
"typecheck:renderer": "cd apps/renderer && npm run typecheck"
},
"devDependencies": {
"@eslint/js": "^9.39.2",

View file

@ -520,16 +520,21 @@ All tests use the in-memory/mocked turn runtime and repo fakes.
## 14. Suggested module layout
```text
apps/x/packages/shared/src/sessions.ts # event schemas, reducer, index types
apps/x/packages/shared/src/sessions.ts # event schemas, reducer, index types
apps/x/packages/core/src/sessions/
apps/x/packages/core/src/runtime/sessions/
sessions.ts # ISessions implementation
api.ts # public contract
repo.ts # ISessionRepo contract
fs-repo.ts # filesystem implementation
index.ts # in-memory index + startup scan
headless.ts # runHeadlessTurn
session-index.ts # in-memory index
bus.ts # index-changed fan-out
```
The headless helper of §11 is implemented as `HeadlessAgentRunner` in
`runtime/assembly/headless.ts` (not under `sessions/`).
Awilix registration mirrors the turn runtime: singleton scope, PROXY
constructor injection, no container resolution from inside the classes.

View file

@ -1888,21 +1888,20 @@ tests for:
This is a suggested organization, not a locked implementation requirement:
```text
apps/x/packages/shared/src/turns.ts
apps/x/packages/shared/src/turns.ts # durable schemas + reducer (unchanged home)
apps/x/packages/core/src/turns/
runtime.ts
reducer.ts # if implementation is re-exported through shared,
# locate pure code to avoid dependency cycles
repo.ts
fs-repo.ts
stream.ts
agent-resolver.ts
context-resolver.ts
model-registry.ts
tool-registry.ts
permission.ts
index.ts
apps/x/packages/core/src/runtime/
turns/ # the engine: runtime.ts, stream, event-hub, context
# resolution/elision, request composer, repos, inspect-cli
bridges/ # real implementations of the engine's seams (agent/tool/
# model resolvers, permission checker/classifier)
sessions/ # session layer (session-design.md)
assembly/ # what an agent is: registry, compose-instructions,
# workspace-context, message-encoding, permission-metadata,
# headless runners, spawn-agent, copilot/, capabilities/,
# skills/
tools/ # builtin-tool catalog + domain modules + exec plumbing
legacy/ # the dying runs engine (engine.ts + runs.ts + repos)
```
The final reducer location must permit both core and renderer to use exactly the

View file

@ -7,10 +7,11 @@
"scripts": {
"build": "rm -rf dist && tsc -p tsconfig.build.json",
"dev": "tsc -w -p tsconfig.build.json",
"typecheck": "tsc --noEmit -p tsconfig.json",
"test": "vitest run",
"test:watch": "vitest",
"inspect-turn": "node dist/turns/inspect-cli.js",
"inspect": "node dist/turns/inspect-cli.js"
"inspect-turn": "node dist/runtime/turns/inspect-cli.js",
"inspect": "node dist/runtime/turns/inspect-cli.js"
},
"dependencies": {
"@agentclientprotocol/claude-agent-acp": "^0.55.0",

View file

@ -4,7 +4,7 @@ import { IAgentScheduleRepo } from "./repo.js";
import { IAgentScheduleStateRepo } from "./state-repo.js";
import { AgentScheduleConfig, AgentScheduleEntry } from "@x/shared/dist/agent-schedule.js";
import { AgentScheduleState, AgentScheduleStateEntry } from "@x/shared/dist/agent-schedule-state.js";
import { startWhenPossible } from "../agents/headless-app.js";
import { startWhenPossible } from "../runtime/assembly/headless-app.js";
import { withUseCase } from "../analytics/use_case.js";
import z from "zod";

View file

@ -1,133 +0,0 @@
// Shared support for the builtin-tools domain modules: the catalog schema
// and the helpers/input-schemas the tool entries use. Extracted verbatim
// from the historical monolith.
import { z, ZodType } from "zod";
import * as path from "path";
import * as os from "os";
import container from "../../../di/container.js";
import { BackgroundTaskSchema, TriggersSchema } from "@x/shared/dist/background-task.js";
import type { CodeRunEvent as CodeRunEventType } from "@x/shared/dist/code-mode.js";
import type { ICodeProjectsRepo } from "../../../code-mode/projects/repo.js";
import * as gitService from "../../../code-mode/git/service.js";
// Inputs for the bg-task builtin tools. Reuse the canonical schema field
// descriptions; only `triggers` gets a tighter contextual override (the
// shared TriggersSchema description is written from the live-note perspective).
export const CreateBackgroundTaskInput = BackgroundTaskSchema.pick({
name: true,
instructions: true,
triggers: true,
model: true,
provider: true,
}).extend({
triggers: TriggersSchema.optional().describe('All three sub-fields (cronExpr, windows, eventMatchCriteria) are independently optional — mix freely. No triggers at all = manual-only (user clicks Run).'),
projectDir: z.string().optional().describe(
"Set this ONLY when the user wants the task to WRITE CODE. An absolute path (or ~/…) to a LOCAL GIT REPOSITORY with at least one commit. It turns this into a *coding task*: each run scans the trigger source for actionable items and implements them autonomously in isolated git worktrees off this repo — never touching the user's checkout. Extract the directory from the user's request (e.g. 'use ~/Work/space/test as the work directory'). Omit for ordinary output/action tasks.",
),
});
export const PatchBackgroundTaskInput = BackgroundTaskSchema.pick({
name: true,
instructions: true,
active: true,
triggers: true,
model: true,
provider: true,
}).partial().extend({
slug: z.string().describe('The slug of the task to update (the folder name under bg-tasks/).'),
triggers: TriggersSchema.optional().describe('Replace the triggers object. To remove all triggers (make manual-only) pass an empty object.'),
projectDir: z.string().optional().describe("Point an existing task at a code repo (or change which one) to make it a coding task. Absolute path or ~/… to a local git repository with at least one commit. Same rules as on create."),
clearModel: z.boolean().optional().describe("Reset the task's model/provider override so it falls back to the default. Use this to unstick a bad/rejected model value (do not also pass model)."),
});
// Turn a user-supplied directory into a registered code project id. Reuses the
// same idempotent registry the Code-section picker writes to (add() validates the
// dir exists & is a directory, and dedupes by resolved path). Returns a soft
// `warning` — not an error — when the repo isn't yet worktree-ready, so the task
// still gets created and the copilot can tell the user what to fix.
export function expandHome(p: string): string {
const t = p.trim();
if (t === '~') return os.homedir();
if (t.startsWith('~/') || t.startsWith(`~${path.sep}`)) return path.join(os.homedir(), t.slice(2));
return t;
}
// Shrink a code-run timeline for durable storage: consecutive same-role message
// chunks merge into one event. Display-lossless — the timeline renderer
// concatenates consecutive messages anyway (CodingRunTimeline) — and typically
// collapses the ~90% of a run's events that are per-token text deltas.
// Everything else (tool calls/updates, plans, permissions) is kept verbatim in
// order: updates are id-keyed transitions and must not be merged.
export function coalesceCodeRunEvents(events: CodeRunEventType[]): CodeRunEventType[] {
const out: CodeRunEventType[] = [];
for (const event of events) {
const last = out[out.length - 1];
if (
event.type === 'message' && last?.type === 'message' && last.role === event.role
) {
out[out.length - 1] = { ...last, text: last.text + event.text };
} else {
out.push(event);
}
}
return out;
}
export async function resolveCodeProject(dirPath: string): Promise<
{ ok: true; projectId: string; path: string; warning?: string } | { ok: false; error: string }
> {
const abs = path.resolve(expandHome(dirPath));
const projectsRepo = container.resolve<ICodeProjectsRepo>('codeProjectsRepo');
let project: Awaited<ReturnType<ICodeProjectsRepo['add']>>;
try {
project = await projectsRepo.add(abs);
} catch (err) {
return { ok: false, error: `Could not use '${dirPath}' as a code directory: ${err instanceof Error ? err.message : String(err)}` };
}
// Worktree isolation needs a real git repo with at least one commit
// (codeSessionService.create throws otherwise). Surface it now as a soft
// warning rather than letting the next run fail silently.
let warning: string | undefined;
try {
const info = await gitService.repoInfo(project.path);
if (!info.isGitRepo) warning = `${project.path} is not a git repository yet — run \`git init\` and make a commit, or the coding sessions will fail.`;
else if (!info.hasCommits) warning = `${project.path} has no commits yet — make an initial commit, or the coding sessions will fail.`;
} catch { /* best effort — worktree creation will surface it later */ }
return { ok: true, projectId: project.id, path: project.path, ...(warning ? { warning } : {}) };
}
// Parser libraries are loaded dynamically inside parseFile.execute()
// to avoid pulling pdfjs-dist's DOM polyfills into the main bundle.
// Import paths are computed so esbuild cannot statically resolve them.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const _importDynamic = new Function('mod', 'return import(mod)') as (mod: string) => Promise<any>;
export const BuiltinToolsSchema = z.record(z.string(), z.object({
description: z.string(),
inputSchema: z.custom<ZodType>(),
execute: z.function({
input: z.any(), // (input, ctx?) => Promise<any>
output: z.promise(z.any()),
}),
isAvailable: z.custom<() => Promise<boolean>>().optional(),
}));
export const LLMPARSE_MIME_TYPES: Record<string, string> = {
'.pdf': 'application/pdf',
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'.doc': 'application/msword',
'.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'.xls': 'application/vnd.ms-excel',
'.csv': 'text/csv',
'.txt': 'text/plain',
'.html': 'text/html',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.gif': 'image/gif',
'.webp': 'image/webp',
'.svg': 'image/svg+xml',
'.bmp': 'image/bmp',
'.tiff': 'image/tiff',
};

View file

@ -1,7 +1,7 @@
import { exec, execSync, spawn, ChildProcess } from 'child_process';
import { promisify } from 'util';
import { getSecurityAllowList } from '../../config/security.js';
import { getExecutionShell } from '../assistant/runtime-context.js';
import { getExecutionShell } from '../../runtime/assembly/copilot/runtime-context.js';
const execPromise = promisify(exec);

View file

@ -26,8 +26,8 @@ import { createProvider } from '../models/models.js';
import { captureLlmUsage } from '../analytics/usage.js';
import { withUseCase } from '../analytics/use_case.js';
import { isSignedIn } from '../account/account.js';
import { createRun, createMessage } from '../runs/runs.js';
import { extractAgentResponse, waitForRunCompletion } from '../agents/utils.js';
import { createRun, createMessage } from '../runtime/legacy/runs.js';
import { extractAgentResponse, waitForRunCompletion } from '../runtime/legacy/utils.js';
import { getBackgroundTaskAgentModel } from '../models/defaults.js';
// Host API — M2 endpoints (spec §7.4§7.7): Composio tools, SSRF-guarded fetch

View file

@ -1,6 +1,6 @@
import z from 'zod';
import { Agent, ToolAttachment } from '@x/shared/dist/agent.js';
import { BuiltinTools } from '../application/lib/builtin-tools.js';
import { BuiltinTools } from '../runtime/tools/catalog.js';
import { KNOWLEDGE_NOTE_STYLE_GUIDE } from '../application/lib/knowledge-note-style.js';
import { WorkDir } from '../config/config.js';

View file

@ -5,7 +5,7 @@ import container from '../di/container.js';
import type { CodeSessionService } from '../code-mode/sessions/service.js';
import type { ICodeProjectsRepo } from '../code-mode/projects/repo.js';
import * as gitService from '../code-mode/git/service.js';
import { extractAgentResponse } from '../agents/utils.js';
import { extractAgentResponse } from '../runtime/legacy/utils.js';
import { withFileLock } from '../knowledge/file-lock.js';
import { fetchTask, taskIndexPath } from './fileops.js';

View file

@ -2,8 +2,8 @@ import type { BackgroundTask, BackgroundTaskTriggerType } from '@x/shared/dist/b
import { PrefixLogger } from '@x/shared/dist/prefix-logger.js';
import { fetchTask, patchTask, prependRunId } from './fileops.js';
import { getBackgroundTaskAgentModel } from '../models/defaults.js';
import { startHeadlessAgent, startWhenPossible } from '../agents/headless-app.js';
import { buildTriggerBlock } from '../agents/build-trigger-block.js';
import { startHeadlessAgent, startWhenPossible } from '../runtime/assembly/headless-app.js';
import { buildTriggerBlock } from '../runtime/assembly/build-trigger-block.js';
import { backgroundTaskBus } from './bus.js';
import { withUseCase } from '../analytics/use_case.js';

View file

@ -1,9 +1,9 @@
import { describe, expect, it, vi } from "vitest";
import type { SessionIndexEntry } from "@x/shared/dist/sessions.js";
import type { TurnStreamEvent } from "@x/shared/dist/turns.js";
import { TurnEventHub } from "../turns/event-hub.js";
import { TurnInputError } from "../turns/api.js";
import type { ISessions } from "../sessions/api.js";
import { TurnEventHub } from "../runtime/turns/event-hub.js";
import { TurnInputError } from "../runtime/turns/api.js";
import type { ISessions } from "../runtime/sessions/api.js";
import { ChannelBridge, type ModelChoice } from "./bridge.js";
const SENDER = "test:1";

View file

@ -1,10 +1,10 @@
import type { SessionIndexEntry } from "@x/shared/dist/sessions.js";
import { reduceTurn, type TurnStreamEvent } from "@x/shared/dist/turns.js";
import { assistantText, lastAssistantText } from "../agents/headless.js";
import { TurnInputError } from "../turns/api.js";
import { ASK_HUMAN_TOOL } from "../turns/bridges/real-agent-resolver.js";
import { TurnNotSettledError, type ISessions } from "../sessions/api.js";
import type { ITurnEventBus } from "../turns/event-hub.js";
import { assistantText, lastAssistantText } from "../runtime/assembly/headless.js";
import { TurnInputError } from "../runtime/turns/api.js";
import { ASK_HUMAN_TOOL } from "../runtime/turns/bridges/real-agent-resolver.js";
import { TurnNotSettledError, type ISessions } from "../runtime/sessions/api.js";
import type { ITurnEventBus } from "../runtime/turns/event-hub.js";
// Transport-agnostic command layer: inbound texts from a messaging channel
// are parsed into commands (list / resume / new / stop / status) or forwarded

View file

@ -4,8 +4,8 @@ import type { z } from "zod";
import type { ChannelsConfig, ChannelsStatus } from "@x/shared/dist/channels.js";
import container from "../di/container.js";
import { WorkDir } from "../config/config.js";
import type { ISessions } from "../sessions/api.js";
import type { ITurnEventBus } from "../turns/event-hub.js";
import type { ISessions } from "../runtime/sessions/api.js";
import type { ITurnEventBus } from "../runtime/turns/event-hub.js";
import { isSignedIn } from "../account/account.js";
import { listGatewayModels } from "../models/gateway.js";
import { listOnboardingModels } from "../models/models-dev.js";

View file

@ -5,11 +5,11 @@ import { WorkDir } from '../../config/config.js';
import type { CodeSession, CodeSessionMode } from '@x/shared/dist/code-sessions.js';
import type { CodingAgent, ApprovalPolicy } from '@x/shared/dist/code-mode.js';
import { RunEvent, MessageEvent } from '@x/shared/dist/runs.js';
import type { IRunsRepo } from '../../runs/repo.js';
import type { IRunsLock } from '../../runs/lock.js';
import type { IRunsRepo } from '../../runtime/legacy/repo.js';
import type { IRunsLock } from '../../runtime/legacy/lock.js';
import type { IBus } from '../../application/lib/bus.js';
import type { IMonotonicallyIncreasingIdGenerator } from '../../application/lib/id-gen.js';
import type { IAbortRegistry } from '../../turns/abort-registry.js';
import type { IAbortRegistry } from '../../runtime/turns/abort-registry.js';
import type { CodeModeManager } from '../acp/manager.js';
import type { CodePermissionRegistry } from '../acp/permission-registry.js';
import type { ICodeSessionsRepo } from './repo.js';
@ -114,7 +114,7 @@ export class CodeSessionService {
// The session is a real run so Rowboat mode (agent runtime) works on it
// directly and the existing runs plumbing (fetch/events/stop) applies.
const { createRun } = await import('../../runs/runs.js');
const { createRun } = await import('../../runtime/legacy/runs.js');
const run = await createRun({
agentId: 'copilot',
useCase: 'code_session',

View file

@ -3,18 +3,18 @@ import { asClass, asFunction, asValue, createContainer, InjectionMode } from "aw
import { WorkDir } from "../config/config.js";
import { FSModelConfigRepo, IModelConfigRepo } from "../models/repo.js";
import { FSMcpConfigRepo, IMcpConfigRepo } from "../mcp/repo.js";
import { FSAgentsRepo, IAgentsRepo } from "../agents/repo.js";
import { FSRunsRepo, IRunsRepo } from "../runs/repo.js";
import { FSAgentsRepo, IAgentsRepo } from "../runtime/assembly/repo.js";
import { FSRunsRepo, IRunsRepo } from "../runtime/legacy/repo.js";
import { IMonotonicallyIncreasingIdGenerator, IdGen } from "../application/lib/id-gen.js";
import { IMessageQueue, InMemoryMessageQueue } from "../application/lib/message-queue.js";
import { IBus, InMemoryBus } from "../application/lib/bus.js";
import { IRunsLock, InMemoryRunsLock } from "../runs/lock.js";
import { IAgentRuntime, AgentRuntime } from "../agents/runtime.js";
import { IRunsLock, InMemoryRunsLock } from "../runtime/legacy/lock.js";
import { IAgentRuntime, AgentRuntime } from "../runtime/legacy/engine.js";
import { FSOAuthRepo, IOAuthRepo } from "../auth/repo.js";
import { FSClientRegistrationRepo, IClientRegistrationRepo } from "../auth/client-repo.js";
import { FSGranolaConfigRepo, IGranolaConfigRepo } from "../knowledge/granola/repo.js";
import { FSCodeModeConfigRepo, ICodeModeConfigRepo } from "../code-mode/repo.js";
import { IAbortRegistry, InMemoryAbortRegistry } from "../turns/abort-registry.js";
import { IAbortRegistry, InMemoryAbortRegistry } from "../runtime/turns/abort-registry.js";
import { FSAgentScheduleRepo, IAgentScheduleRepo } from "../agent-schedule/repo.js";
import { FSAgentScheduleStateRepo, IAgentScheduleStateRepo } from "../agent-schedule/state-repo.js";
import { FSSlackConfigRepo, ISlackConfigRepo } from "../slack/repo.js";
@ -28,33 +28,33 @@ import { CodeSessionService } from "../code-mode/sessions/service.js";
import { CodeSessionStatusTracker } from "../code-mode/sessions/status-tracker.js";
import type { IBrowserControlService } from "../application/browser-control/service.js";
import type { INotificationService } from "../application/notification/service.js";
import { SystemClock, type IClock } from "../turns/clock.js";
import { FSTurnRepo } from "../turns/fs-repo.js";
import type { ITurnRepo } from "../turns/repo.js";
import type { IContextResolver } from "../turns/context-resolver.js";
import { createContextResolver } from "../turns/context-elision.js";
import { EmitterTurnLifecycleBus, type ITurnLifecycleBus } from "../turns/bus.js";
import { TurnEventHub, type ITurnEventBus } from "../turns/event-hub.js";
import { RealUsageReporter } from "../turns/bridges/real-usage-reporter.js";
import type { IUsageReporter } from "../turns/usage-reporter.js";
import { TurnRuntime } from "../turns/runtime.js";
import type { ITurnRuntime } from "../turns/api.js";
import type { IAgentResolver } from "../turns/agent-resolver.js";
import type { IModelRegistry } from "../turns/model-registry.js";
import type { IToolRegistry } from "../turns/tool-registry.js";
import type { IPermissionChecker, IPermissionClassifier } from "../turns/permission.js";
import { RealAgentResolver } from "../turns/bridges/real-agent-resolver.js";
import { InlineAgentResolver } from "../turns/bridges/inline-agent-resolver.js";
import { DispatchingAgentResolver } from "../turns/bridges/agent-resolver-dispatch.js";
import { RealModelRegistry } from "../turns/bridges/real-model-registry.js";
import { RealToolRegistry } from "../turns/bridges/real-tool-registry.js";
import { RealPermissionChecker } from "../turns/bridges/real-permission-checker.js";
import { RealPermissionClassifier } from "../turns/bridges/real-permission-classifier.js";
import { FSSessionRepo } from "../sessions/fs-repo.js";
import type { ISessionRepo } from "../sessions/repo.js";
import { EmitterSessionBus, type ISessionBus } from "../sessions/bus.js";
import { SessionsImpl } from "../sessions/sessions.js";
import type { ISessions } from "../sessions/api.js";
import { SystemClock, type IClock } from "../runtime/turns/clock.js";
import { FSTurnRepo } from "../runtime/turns/fs-repo.js";
import type { ITurnRepo } from "../runtime/turns/repo.js";
import type { IContextResolver } from "../runtime/turns/context-resolver.js";
import { createContextResolver } from "../runtime/turns/context-elision.js";
import { EmitterTurnLifecycleBus, type ITurnLifecycleBus } from "../runtime/turns/bus.js";
import { TurnEventHub, type ITurnEventBus } from "../runtime/turns/event-hub.js";
import { RealUsageReporter } from "../runtime/turns/bridges/real-usage-reporter.js";
import type { IUsageReporter } from "../runtime/turns/usage-reporter.js";
import { TurnRuntime } from "../runtime/turns/runtime.js";
import type { ITurnRuntime } from "../runtime/turns/api.js";
import type { IAgentResolver } from "../runtime/turns/agent-resolver.js";
import type { IModelRegistry } from "../runtime/turns/model-registry.js";
import type { IToolRegistry } from "../runtime/turns/tool-registry.js";
import type { IPermissionChecker, IPermissionClassifier } from "../runtime/turns/permission.js";
import { RealAgentResolver } from "../runtime/turns/bridges/real-agent-resolver.js";
import { InlineAgentResolver } from "../runtime/turns/bridges/inline-agent-resolver.js";
import { DispatchingAgentResolver } from "../runtime/turns/bridges/agent-resolver-dispatch.js";
import { RealModelRegistry } from "../runtime/turns/bridges/real-model-registry.js";
import { RealToolRegistry } from "../runtime/turns/bridges/real-tool-registry.js";
import { RealPermissionChecker } from "../runtime/turns/bridges/real-permission-checker.js";
import { RealPermissionClassifier } from "../runtime/turns/bridges/real-permission-classifier.js";
import { FSSessionRepo } from "../runtime/sessions/fs-repo.js";
import type { ISessionRepo } from "../runtime/sessions/repo.js";
import { EmitterSessionBus, type ISessionBus } from "../runtime/sessions/bus.js";
import { SessionsImpl } from "../runtime/sessions/sessions.js";
import type { ISessions } from "../runtime/sessions/api.js";
import {
DefaultModelResolver,
type IDefaultModelResolver,
@ -62,7 +62,7 @@ import {
import {
HeadlessAgentRunner,
type IHeadlessAgentRunner,
} from "../agents/headless.js";
} from "../runtime/assembly/headless.js";
const container = createContainer({
injectionMode: InjectionMode.PROXY,

View file

@ -2,9 +2,9 @@ import fs from 'fs';
import path from 'path';
import { google } from 'googleapis';
import { WorkDir } from '../config/config.js';
import { runWhenPossible } from '../agents/headless-app.js';
import { runWhenPossible } from '../runtime/assembly/headless-app.js';
import { getKgModel } from '../models/defaults.js';
import { getErrorDetails } from '../agents/utils.js';
import { getErrorDetails } from '../runtime/legacy/utils.js';
import { serviceLogger } from '../services/service_logger.js';
import { loadUserConfig, updateUserEmail } from '../config/user_config.js';
import { GoogleClientFactory } from './google-client-factory.js';

View file

@ -2,8 +2,8 @@ import fs from 'fs';
import path from 'path';
import { WorkDir } from '../config/config.js';
import { getKgModel } from '../models/defaults.js';
import { runWhenPossible, toolInputPaths } from '../agents/headless-app.js';
import { getErrorDetails } from '../agents/utils.js';
import { runWhenPossible, toolInputPaths } from '../runtime/assembly/headless-app.js';
import { getErrorDetails } from '../runtime/legacy/utils.js';
import { serviceLogger, type ServiceRunContext } from '../services/service_logger.js';
import {
loadState,

View file

@ -1,4 +1,4 @@
import { BuiltinTools } from '../application/lib/builtin-tools.js';
import { BuiltinTools } from '../runtime/tools/catalog.js';
export function getRaw(): string {
// code_agent_run needs an interactive UI to answer its permission asks; exclude it

View file

@ -3,7 +3,7 @@ import path from 'path';
import { CronExpressionParser } from 'cron-parser';
import { generateText } from 'ai';
import { WorkDir } from '../config/config.js';
import { runWhenPossible } from '../agents/headless-app.js';
import { runWhenPossible } from '../runtime/assembly/headless-app.js';
import { getKgModel } from '../models/defaults.js';
import container from '../di/container.js';
import type { IModelConfigRepo } from '../models/repo.js';

View file

@ -1,9 +1,9 @@
import fs from 'fs';
import path from 'path';
import { WorkDir } from '../config/config.js';
import { runWhenPossible, toolInputPaths } from '../agents/headless-app.js';
import { runWhenPossible, toolInputPaths } from '../runtime/assembly/headless-app.js';
import { getKgModel } from '../models/defaults.js';
import { getErrorDetails } from '../agents/utils.js';
import { getErrorDetails } from '../runtime/legacy/utils.js';
import { serviceLogger } from '../services/service_logger.js';
import { limitEventItems } from './limit_event_items.js';
import {

View file

@ -1,6 +1,6 @@
import z from 'zod';
import { Agent, ToolAttachment } from '@x/shared/dist/agent.js';
import { BuiltinTools } from '../../application/lib/builtin-tools.js';
import { BuiltinTools } from '../../runtime/tools/catalog.js';
import { KNOWLEDGE_NOTE_STYLE_GUIDE } from '../../application/lib/knowledge-note-style.js';
import { WorkDir } from '../../config/config.js';

View file

@ -1,9 +1,9 @@
import type { LiveNote, LiveNoteTriggerType } from '@x/shared/dist/live-note.js';
import { fetchLiveNote, patchLiveNote, readNoteBody } from './fileops.js';
import { getLiveNoteAgentModel } from '../../models/defaults.js';
import { startHeadlessAgent, startWhenPossible } from '../../agents/headless-app.js';
import { startHeadlessAgent, startWhenPossible } from '../../runtime/assembly/headless-app.js';
import { withUseCase } from '../../analytics/use_case.js';
import { buildTriggerBlock } from '../../agents/build-trigger-block.js';
import { buildTriggerBlock } from '../../runtime/assembly/build-trigger-block.js';
import { liveNoteBus } from './bus.js';
import { PrefixLogger } from '@x/shared/dist/prefix-logger.js';

View file

@ -1,9 +1,9 @@
import fs from 'fs';
import path from 'path';
import { WorkDir } from '../config/config.js';
import { runWhenPossible, toolInputPaths } from '../agents/headless-app.js';
import { runWhenPossible, toolInputPaths } from '../runtime/assembly/headless-app.js';
import { getKgModel } from '../models/defaults.js';
import { getErrorDetails } from '../agents/utils.js';
import { getErrorDetails } from '../runtime/legacy/utils.js';
import { serviceLogger } from '../services/service_logger.js';
import { limitEventItems } from './limit_event_items.js';
import {

View file

@ -5,8 +5,8 @@ import path from "node:path";
import { fileURLToPath } from "node:url";
import { reduceTurn } from "@x/shared/dist/turns.js";
import { reduceSession } from "@x/shared/dist/sessions.js";
import { FSTurnRepo } from "../../turns/fs-repo.js";
import { FSSessionRepo } from "../../sessions/fs-repo.js";
import { FSTurnRepo } from "../../runtime/turns/fs-repo.js";
import { FSSessionRepo } from "../../runtime/sessions/fs-repo.js";
import { migrateRuns } from "./migrate.js";
const fixturesDir = path.join(

View file

@ -1,7 +1,7 @@
import fs from 'fs';
import path from 'path';
import { WorkDir } from '../config/config.js';
import { runWhenPossible } from '../agents/headless-app.js';
import { runWhenPossible } from '../runtime/assembly/headless-app.js';
import { getKgModel } from '../models/defaults.js';
import {
loadConfig,

View file

@ -1,4 +0,0 @@
import container from "../di/container.js";
import { IBus } from "../application/lib/bus.js";
export const bus = container.resolve<IBus>('bus');

View file

@ -1,12 +1,12 @@
import { MODE_CAPABILITIES } from "../application/assistant/capabilities/modes.js";
import { MODE_CAPABILITIES } from "./capabilities/modes.js";
import {
AGENT_NOTES_CAPABILITY,
WORK_DIRECTORY_CAPABILITY,
} from "../application/assistant/capabilities/workspace.js";
} from "./capabilities/workspace.js";
import type {
CapabilityContext,
ModeFlags,
} from "../application/assistant/capabilities/types.js";
} from "./capabilities/types.js";
// Everything that composes into the system prompt, in composition order.
const PROMPT_CAPABILITIES = [

View file

@ -1,16 +1,16 @@
import { buildAvailableSkillCatalog } from "./skills/index.js";
import { buildAvailableSkillCatalog } from "../skills/index.js";
import { getRuntimeContext, getRuntimeContextPrompt } from "./runtime-context.js";
import {
isCodeModeAvailable,
isComposioAvailable,
isGoogleConnected,
isSlackAvailable,
} from "./connections.js";
import { composioAccountsRepo } from "../../composio/repo.js";
import { isConfigured as isComposioConfigured } from "../../composio/client.js";
} from "../connections.js";
import { composioAccountsRepo } from "../../../composio/repo.js";
import { isConfigured as isComposioConfigured } from "../../../composio/client.js";
import { CURATED_TOOLKITS } from "@x/shared/dist/composio.js";
import { knowledgeSourcesRepo } from "../../knowledge/sources/repo.js";
import { listApps } from "../../apps/indexer.js";
import { knowledgeSourcesRepo } from "../../../knowledge/sources/repo.js";
import { listApps } from "../../../apps/indexer.js";
const runtimeContextPrompt = getRuntimeContextPrompt(getRuntimeContext());

View file

@ -1,6 +1,6 @@
import container from "../di/container.js";
import { chatActivity } from "../application/lib/chat-activity.js";
import { shouldDeferBackgroundTasks } from "../models/defaults.js";
import container from "../../di/container.js";
import { chatActivity } from "../../application/lib/chat-activity.js";
import { shouldDeferBackgroundTasks } from "../../models/defaults.js";
import {
type HeadlessAgentHandle,
type HeadlessAgentOptions,

View file

@ -14,7 +14,7 @@ import {
lastAssistantText,
toolInputPaths,
} from "./headless.js";
import type { IDefaultModelResolver } from "../models/default-model-resolver.js";
import type { IDefaultModelResolver } from "../../models/default-model-resolver.js";
type TEvent = z.infer<typeof TurnEvent>;
@ -252,7 +252,7 @@ describe("HeadlessAgentRunner", () => {
const { runner, resolve } = createRunner(runtime);
await runner.start({ agentId: "worker", message: "go" });
expect(resolve).not.toHaveBeenCalled();
expect(runtime.createInputs[0].agent.overrides).toBeUndefined();
expect(runtime.createInputs[0].agent).toEqual({ agentId: "worker" });
});
it("uses an injected default only for a partial model override", async () => {
@ -264,8 +264,9 @@ describe("HeadlessAgentRunner", () => {
model: "custom-model",
});
expect(resolve).toHaveBeenCalledOnce();
expect(runtime.createInputs[0].agent.overrides).toEqual({
model: { provider: "default-provider", model: "custom-model" },
expect(runtime.createInputs[0].agent).toEqual({
agentId: "worker",
overrides: { model: { provider: "default-provider", model: "custom-model" } },
});
});

View file

@ -6,7 +6,7 @@ import {
type TurnState,
} from "@x/shared/dist/turns.js";
import type { ITurnRuntime, TurnOutcome } from "../turns/api.js";
import type { IDefaultModelResolver } from "../models/default-model-resolver.js";
import type { IDefaultModelResolver } from "../../models/default-model-resolver.js";
// Drop-in replacement for the old headless runs pattern
// (createRun → createMessage → waitForRunCompletion → extractAgentResponse):

View file

@ -4,14 +4,14 @@
// engine file so the turn-runtime bridges no longer depend on it.
import path from "path";
import { WorkDir } from "../config/config.js";
import { WorkDir } from "../../config/config.js";
import { ToolAttachment } from "@x/shared/dist/agent.js";
import { ToolCallPart } from "@x/shared/dist/message.js";
import { z } from "zod";
import { ToolPermissionMetadata } from "@x/shared/dist/runs.js";
import { isBlocked, extractCommandNames } from "../application/lib/command-executor.js";
import { getFileAccessAllowList, type FileAccessGrant, type FileAccessOperation } from "../config/security.js";
import { resolveFilePathForPermission } from "../filesystem/files.js";
import { isBlocked, extractCommandNames } from "../../application/lib/command-executor.js";
import { getFileAccessAllowList, type FileAccessGrant, type FileAccessOperation } from "../../config/security.js";
import { resolveFilePathForPermission } from "../../filesystem/files.js";
type ToolPermissionMetadataValue = z.infer<typeof ToolPermissionMetadata>;

View file

@ -1,16 +1,16 @@
import type { z } from "zod";
import { Agent } from "@x/shared/dist/agent.js";
import { parseFrontmatter } from "../application/lib/parse-frontmatter.js";
import { buildCopilotAgent } from "../application/assistant/agent.js";
import { buildBackgroundTaskAgent } from "../background-tasks/agent.js";
import { buildLiveNoteAgent } from "../knowledge/live-note/agent.js";
import { getRaw as getNoteCreationRaw } from "../knowledge/note_creation.js";
import { getRaw as getNoteCurationRaw } from "../knowledge/note_curation.js";
import { getRaw as getLabelingAgentRaw } from "../knowledge/labeling_agent.js";
import { getRaw as getNoteTaggingAgentRaw } from "../knowledge/note_tagging_agent.js";
import { getRaw as getInlineTaskAgentRaw } from "../knowledge/inline_task_agent.js";
import { getRaw as getAgentNotesAgentRaw } from "../knowledge/agent_notes_agent.js";
import { lazyResolve } from "../di/lazy-resolve.js";
import { parseFrontmatter } from "../../application/lib/parse-frontmatter.js";
import { buildCopilotAgent } from "./copilot/agent.js";
import { buildBackgroundTaskAgent } from "../../background-tasks/agent.js";
import { buildLiveNoteAgent } from "../../knowledge/live-note/agent.js";
import { getRaw as getNoteCreationRaw } from "../../knowledge/note_creation.js";
import { getRaw as getNoteCurationRaw } from "../../knowledge/note_curation.js";
import { getRaw as getLabelingAgentRaw } from "../../knowledge/labeling_agent.js";
import { getRaw as getNoteTaggingAgentRaw } from "../../knowledge/note_tagging_agent.js";
import { getRaw as getInlineTaskAgentRaw } from "../../knowledge/inline_task_agent.js";
import { getRaw as getAgentNotesAgentRaw } from "../../knowledge/agent_notes_agent.js";
import { lazyResolve } from "../../di/lazy-resolve.js";
import type { IAgentsRepo } from "./repo.js";
// The registry of built-in agents: one table instead of the historical

View file

@ -1,11 +1,11 @@
import { WorkDir } from "../config/config.js";
import { WorkDir } from "../../config/config.js";
import fs from "fs/promises";
import { glob } from "node:fs/promises";
import path from "path";
import z from "zod";
import { Agent } from "@x/shared/dist/agent.js";
import { stringify } from "yaml";
import { parseFrontmatter } from "../application/lib/parse-frontmatter.js";
import { parseFrontmatter } from "../../application/lib/parse-frontmatter.js";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const UpdateAgentSchema = Agent.omit({ name: true });

View file

@ -3,7 +3,7 @@ import path from "node:path";
import { homedir } from "node:os";
import { WorkDir } from "../../../config/config.js";
import type { ModelCapability } from "../capabilities/types.js";
import { splitFrontmatter } from "../../lib/parse-frontmatter.js";
import { splitFrontmatter } from "../../../application/lib/parse-frontmatter.js";
/**
* A skill discovered on disk: structurally the model-activated capability

View file

@ -1,4 +1,4 @@
import { KNOWLEDGE_NOTE_STYLE_GUIDE } from '../../../lib/knowledge-note-style.js';
import { KNOWLEDGE_NOTE_STYLE_GUIDE } from '../../../../application/lib/knowledge-note-style.js';
export const skill = String.raw`
# Document Collaboration Skill

View file

@ -103,7 +103,7 @@ describe("skills index (disk skill merge layer)", () => {
const skills = await loadSkillsIndex();
const resolved = skills.resolveSkill("meeting-prep");
expect(resolved?.catalogPath).toBe("src/application/assistant/skills/meeting-prep/skill.ts");
expect(resolved?.catalogPath).toBe("src/runtime/assembly/skills/meeting-prep/skill.ts");
expect(resolved?.content).not.toContain("DISK CONTENT MARKER");
const catalog = skills.buildSkillCatalog();
@ -178,7 +178,7 @@ describe("capability activation boundary", () => {
summary: "a genuine model-activated skill",
content: "guidance",
tools: ["file-readText"],
catalogPath: "src/application/assistant/skills/real-skill/skill.ts",
catalogPath: "src/runtime/assembly/skills/real-skill/skill.ts",
};
const mixed = [model, eager];
@ -199,6 +199,18 @@ describe("capability activation boundary", () => {
expect(catalog).toContain(id);
}
});
it("resolves bundled skills by the advertised path and by the pre-reorg legacy path", async () => {
// The catalog advertises the post-reorg source path; agent snapshots baked
// before the move still reference the old application/assistant prefix.
// Both must resolve to the same skill.
const { resolveSkill } = await loadSkillsIndex();
const advertised = resolveSkill("src/runtime/assembly/skills/meeting-prep/skill.ts");
const legacy = resolveSkill("src/application/assistant/skills/meeting-prep/skill.ts");
expect(advertised?.id).toBe("meeting-prep");
expect(legacy?.id).toBe("meeting-prep");
expect(legacy?.content).toBe(advertised?.content);
});
});
describe("availability (catalog visibility)", () => {

View file

@ -31,7 +31,10 @@ import appsSkill from "./apps/skill.js";
import slackSkill from "./slack/skill.js";
const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url));
const CATALOG_PREFIX = "src/application/assistant/skills";
const CATALOG_PREFIX = "src/runtime/assembly/skills";
// Pre-reorg home of the bundled skills. Agent snapshots baked before the move
// carry loadSkill references under this prefix, so it stays a resolvable alias.
const LEGACY_CATALOG_PREFIX = "src/application/assistant/skills";
// console.log(liveNoteSkill);
@ -355,6 +358,8 @@ for (const entry of bundledEntries) {
`skills/${entry.id}/skill.js`,
`${CATALOG_PREFIX}/${entry.id}/skill.ts`,
`${CATALOG_PREFIX}/${entry.id}/skill.js`,
`${LEGACY_CATALOG_PREFIX}/${entry.id}/skill.ts`,
`${LEGACY_CATALOG_PREFIX}/${entry.id}/skill.js`,
absoluteTs,
absoluteJs,
];

View file

@ -2,7 +2,7 @@ import chokidar, { type FSWatcher } from "chokidar";
import fs from "node:fs";
import { SKILL_ROOTS } from "./disk-loader.js";
import { refreshDiskSkills } from "./index.js";
import { invalidateCopilotInstructionsCache } from "../instructions.js";
import { invalidateCopilotInstructionsCache } from "../copilot/instructions.js";
// The skills CLI writes many files per install (~13 paths for one skill), so we
// coalesce a burst of events into a single refresh.

View file

@ -230,7 +230,7 @@ export async function runSpawnedAgent(
async function resolveServices(): Promise<
NonNullable<SpawnedAgentCallbacks["services"]>
> {
const { lazyResolve } = await import("../di/lazy-resolve.js");
const { lazyResolve } = await import("../../di/lazy-resolve.js");
return {
turnRuntime:
await lazyResolve<import("../turns/api.js").ITurnRuntime>(

View file

@ -1,6 +1,6 @@
import fs from "fs";
import path from "path";
import { WorkDir } from "../config/config.js";
import { WorkDir } from "../../config/config.js";
import { hasWorkspaceContext } from "./registry.js";
// Workspace context for agent assembly: agent notes (global) and the user's

View file

@ -0,0 +1,4 @@
import container from "../../di/container.js";
import { IBus } from "../../application/lib/bus.js";
export const bus = container.resolve<IBus>('bus');

View file

@ -4,32 +4,32 @@ import { AssistantContentPart, AssistantMessage, MessageList, ProviderOptions, T
import { LanguageModel, stepCountIs, streamText, tool, Tool, ToolSet } from "ai";
import { z } from "zod";
import { LlmStepStreamEvent } from "@x/shared/dist/llm-step-events.js";
import { execTool } from "../application/lib/exec-tool.js";
import { TOOL_ADDITIONS_KEY } from "../application/lib/tool-additions.js";
import { execTool } from "../tools/exec-tool.js";
import { TOOL_ADDITIONS_KEY } from "../tools/tool-additions.js";
import { AskHumanRequestEvent, RunEvent, ToolPermissionRequestEvent } from "@x/shared/dist/runs.js";
import { BuiltinTools } from "../application/lib/builtin-tools.js";
import { hasWorkspaceContext, loadAgent } from "./registry.js";
import { composeSystemInstructions } from "./compose-instructions.js";
import { convertFromMessages } from "./message-encoding.js";
import { getToolPermissionMetadata } from "./permission-metadata.js";
import { loadWorkspaceContext } from "./workspace-context.js";
import { extractCommandNames } from "../application/lib/command-executor.js";
import { type FileAccessGrant } from "../config/security.js";
import { notifyIfEnabled } from "../application/notification/notifier.js";
import { IModelConfigRepo } from "../models/repo.js";
import { createLanguageModel } from "../models/models.js";
import { chatActivity } from "../application/lib/chat-activity.js";
import { resolveProviderConfig } from "../models/defaults.js";
import { IMonotonicallyIncreasingIdGenerator } from "../application/lib/id-gen.js";
import { IBus } from "../application/lib/bus.js";
import { IMessageQueue, type MiddlePaneContext } from "../application/lib/message-queue.js";
import { IRunsRepo } from "../runs/repo.js";
import { IRunsLock } from "../runs/lock.js";
import { BuiltinTools } from "../tools/catalog.js";
import { hasWorkspaceContext, loadAgent } from "../assembly/registry.js";
import { composeSystemInstructions } from "../assembly/compose-instructions.js";
import { convertFromMessages } from "../assembly/message-encoding.js";
import { getToolPermissionMetadata } from "../assembly/permission-metadata.js";
import { loadWorkspaceContext } from "../assembly/workspace-context.js";
import { extractCommandNames } from "../../application/lib/command-executor.js";
import { type FileAccessGrant } from "../../config/security.js";
import { notifyIfEnabled } from "../../application/notification/notifier.js";
import { IModelConfigRepo } from "../../models/repo.js";
import { createLanguageModel } from "../../models/models.js";
import { chatActivity } from "../../application/lib/chat-activity.js";
import { resolveProviderConfig } from "../../models/defaults.js";
import { IMonotonicallyIncreasingIdGenerator } from "../../application/lib/id-gen.js";
import { IBus } from "../../application/lib/bus.js";
import { IMessageQueue, type MiddlePaneContext } from "../../application/lib/message-queue.js";
import { IRunsRepo } from "./repo.js";
import { IRunsLock } from "./lock.js";
import { IAbortRegistry } from "../turns/abort-registry.js";
import { PrefixLogger } from "@x/shared";
import { captureLlmUsage } from "../analytics/usage.js";
import { enterUseCase, withUseCase, type UseCase } from "../analytics/use_case.js";
import { classifyToolPermissions, type AutoPermissionCandidate } from "../security/auto-permission-classifier.js";
import { captureLlmUsage } from "../../analytics/usage.js";
import { enterUseCase, withUseCase, type UseCase } from "../../analytics/use_case.js";
import { classifyToolPermissions, type AutoPermissionCandidate } from "../../security/auto-permission-classifier.js";
function formatCurrentDateTime(now: Date): string {
return now.toLocaleString('en-US', {

View file

@ -1,12 +1,12 @@
import z from "zod";
import { IMonotonicallyIncreasingIdGenerator } from "../application/lib/id-gen.js";
import { WorkDir } from "../config/config.js";
import { IMonotonicallyIncreasingIdGenerator } from "../../application/lib/id-gen.js";
import { WorkDir } from "../../config/config.js";
import path from "path";
import fsp from "fs/promises";
import fs from "fs";
import readline from "readline";
import { Run, RunEvent, StartEvent, ListRunsResponse, MessageEvent, UseCase } from "@x/shared/dist/runs.js";
import { getDefaultModelAndProvider } from "../models/defaults.js";
import { getDefaultModelAndProvider } from "../../models/defaults.js";
/**
* Reading-only schemas: extend the canonical `StartEvent` / `RunEvent` to

View file

@ -1,18 +1,18 @@
import z from "zod";
import container from "../di/container.js";
import { IMessageQueue, UserMessageContentType, VoiceOutputMode, MiddlePaneContext } from "../application/lib/message-queue.js";
import container from "../../di/container.js";
import { IMessageQueue, UserMessageContentType, VoiceOutputMode, MiddlePaneContext } from "../../application/lib/message-queue.js";
import { AskHumanResponseEvent, ToolPermissionRequestEvent, ToolPermissionResponseEvent, CreateRunOptions, Run, ListRunsResponse, ToolPermissionAuthorizePayload, AskHumanResponsePayload } from "@x/shared/dist/runs.js";
import { IRunsRepo } from "./repo.js";
import { ICodeSessionsRepo } from "../code-mode/sessions/repo.js";
import { IAgentRuntime } from "../agents/runtime.js";
import { IBus } from "../application/lib/bus.js";
import { ICodeSessionsRepo } from "../../code-mode/sessions/repo.js";
import { IAgentRuntime } from "./engine.js";
import { IBus } from "../../application/lib/bus.js";
import { IAbortRegistry } from "../turns/abort-registry.js";
import { IRunsLock } from "./lock.js";
import { forceCloseAllMcpClients } from "../mcp/mcp.js";
import { extractCommandNames } from "../application/lib/command-executor.js";
import { addFileAccessGrant, addToSecurityConfig } from "../config/security.js";
import { loadAgent } from "../agents/registry.js";
import { getDefaultModelAndProvider } from "../models/defaults.js";
import { forceCloseAllMcpClients } from "../../mcp/mcp.js";
import { extractCommandNames } from "../../application/lib/command-executor.js";
import { addFileAccessGrant, addToSecurityConfig } from "../../config/security.js";
import { loadAgent } from "../assembly/registry.js";
import { getDefaultModelAndProvider } from "../../models/defaults.js";
export async function createRun(opts: z.infer<typeof CreateRunOptions>): Promise<z.infer<typeof Run>> {
const repo = container.resolve<IRunsRepo>('runsRepo');

View file

@ -1,5 +1,5 @@
import { bus } from "../runs/bus.js";
import { fetchRun } from "../runs/runs.js";
import { bus } from "./bus.js";
import { fetchRun } from "./runs.js";
type RunRecord = Awaited<ReturnType<typeof fetchRun>>;

View file

@ -19,8 +19,8 @@ import {
isInlineAgentRequest,
reduceTurn,
} from "@x/shared/dist/turns.js";
import type { IMonotonicallyIncreasingIdGenerator } from "../application/lib/id-gen.js";
import { chatActivity } from "../application/lib/chat-activity.js";
import type { IMonotonicallyIncreasingIdGenerator } from "../../application/lib/id-gen.js";
import { chatActivity } from "../../application/lib/chat-activity.js";
import type {
ITurnRuntime,
Turn,

View file

@ -2,8 +2,8 @@ import * as os from "os";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { CodeRunEvent } from "@x/shared/dist/code-mode.js";
import container from "../../di/container.js";
import { InMemoryAbortRegistry } from "../../turns/abort-registry.js";
import { BuiltinTools, coalesceCodeRunEvents } from "./builtin-tools.js";
import { InMemoryAbortRegistry } from "../turns/abort-registry.js";
import { BuiltinTools, coalesceCodeRunEvents } from "./catalog.js";
import type { ToolContext } from "./exec-tool.js";
// A real directory: code_agent_run validates the cwd exists before spawning.

View file

@ -1,29 +1,29 @@
import { z } from "zod";
import { resolveSkill, availableSkills, skillToolNames, setBuiltinToolsSkillTools } from "../assistant/skills/index.js";
import { COPILOT_BASE_TOOLS } from "../assistant/base-tools.js";
import { builtinToolDescriptor } from "../../turns/bridges/builtin-descriptors.js";
import { resolveSkill, availableSkills, skillToolNames, setBuiltinToolsSkillTools } from "../assembly/skills/index.js";
import { COPILOT_BASE_TOOLS } from "../assembly/copilot/base-tools.js";
import { builtinToolDescriptor } from "./descriptors.js";
import { TOOL_ADDITIONS_KEY } from "./tool-additions.js";
import type { ToolDescriptor } from "@x/shared/dist/turns.js";
import { SPAWN_AGENT_TOOL_NAME } from "@x/shared/dist/turns.js";
import { SPAWN_AGENT_DESCRIPTION, SpawnAgentInput } from "../../agents/spawn-agent.js";
import { SPAWN_AGENT_DESCRIPTION, SpawnAgentInput } from "../assembly/spawn-agent.js";
import type { ToolContext } from "./exec-tool.js";
import { fileTools } from "./builtin-tools/files.js";
import { parsingTools } from "./builtin-tools/parsing.js";
import { agentAnalysisTools } from "./builtin-tools/agent-analysis.js";
import { mcpTools } from "./builtin-tools/mcp.js";
import { shellTools } from "./builtin-tools/shell.js";
import { codeAgentRunTools, codeTaskTools } from "./builtin-tools/code.js";
import { browserTools } from "./builtin-tools/browser.js";
import { appNavigationTools, appDataTools } from "./builtin-tools/app.js";
import { webSearchTools, fetchUrlTools } from "./builtin-tools/web.js";
import { memoryTools } from "./builtin-tools/memory.js";
import { composioTools } from "./builtin-tools/composio.js";
import { modelTools } from "./builtin-tools/models.js";
import { liveNoteTools } from "./builtin-tools/live-note.js";
import { backgroundTaskTools } from "./builtin-tools/background-tasks.js";
import { notificationTools } from "./builtin-tools/notifications.js";
import { BuiltinToolsSchema } from "./builtin-tools/support.js";
export { coalesceCodeRunEvents } from "./builtin-tools/support.js";
import { fileTools } from "./domains/files.js";
import { parsingTools } from "./domains/parsing.js";
import { agentAnalysisTools } from "./domains/agent-analysis.js";
import { mcpTools } from "./domains/mcp.js";
import { shellTools } from "./domains/shell.js";
import { codeAgentRunTools, codeTaskTools } from "./domains/code.js";
import { browserTools } from "./domains/browser.js";
import { appNavigationTools, appDataTools } from "./domains/app.js";
import { webSearchTools, fetchUrlTools } from "./domains/web.js";
import { memoryTools } from "./domains/memory.js";
import { composioTools } from "./domains/composio.js";
import { modelTools } from "./domains/models.js";
import { liveNoteTools } from "./domains/live-note.js";
import { backgroundTaskTools } from "./domains/background-tasks.js";
import { notificationTools } from "./domains/notifications.js";
import { BuiltinToolsSchema } from "./types.js";
export { coalesceCodeRunEvents } from "./domains/code.js";
// The builtin-tool catalog, assembled from domain modules
// (./builtin-tools/*). SPREAD ORDER IS LOAD-BEARING: catalog key order is
@ -39,7 +39,7 @@ export const BuiltinTools: z.infer<typeof BuiltinToolsSchema> = {
loadSkill: {
description: "Load a Rowboat skill definition into context by fetching its guidance string",
inputSchema: z.object({
skillName: z.string().describe("Skill identifier or path (e.g., 'workflow-run-ops' or 'src/application/assistant/skills/workflow-run-ops/skill.ts')"),
skillName: z.string().describe("Skill identifier or path (e.g., 'workflow-run-ops' or 'src/runtime/assembly/skills/workflow-run-ops/skill.ts')"),
}),
execute: async ({ skillName }: { skillName: string }) => {
const resolved = resolveSkill(skillName);
@ -101,7 +101,7 @@ export const BuiltinTools: z.infer<typeof BuiltinToolsSchema> = {
// builtin:spawn-agent in RealToolRegistry with a dedicated handler
// that also records the parent→child link as durable tool progress.
execute: async (input: unknown, ctx?: ToolContext) => {
const { runSpawnedAgent } = await import("../../agents/spawn-agent.js");
const { runSpawnedAgent } = await import("../assembly/spawn-agent.js");
const result = await runSpawnedAgent(input, {
parentTurnId: ctx?.runId ?? "",
signal: ctx?.signal ?? new AbortController().signal,

Some files were not shown because too many files have changed in this diff Show more