mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-12 21:02:17 +02:00
refactor(x/core): inject headless agent dependencies
This commit is contained in:
parent
eaa55df161
commit
0e316d1273
14 changed files with 191 additions and 80 deletions
|
|
@ -4,7 +4,7 @@ import { IAgentScheduleRepo } from "./repo.js";
|
||||||
import { IAgentScheduleStateRepo } from "./state-repo.js";
|
import { IAgentScheduleStateRepo } from "./state-repo.js";
|
||||||
import { AgentScheduleConfig, AgentScheduleEntry } from "@x/shared/dist/agent-schedule.js";
|
import { AgentScheduleConfig, AgentScheduleEntry } from "@x/shared/dist/agent-schedule.js";
|
||||||
import { AgentScheduleState, AgentScheduleStateEntry } from "@x/shared/dist/agent-schedule-state.js";
|
import { AgentScheduleState, AgentScheduleStateEntry } from "@x/shared/dist/agent-schedule-state.js";
|
||||||
import { startHeadlessAgent } from "../agents/headless.js";
|
import { startHeadlessAgent } from "../agents/headless-app.js";
|
||||||
import { withUseCase } from "../analytics/use_case.js";
|
import { withUseCase } from "../analytics/use_case.js";
|
||||||
import z from "zod";
|
import z from "zod";
|
||||||
|
|
||||||
|
|
|
||||||
25
apps/x/packages/core/src/agents/headless-app.ts
Normal file
25
apps/x/packages/core/src/agents/headless-app.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import container from "../di/container.js";
|
||||||
|
import {
|
||||||
|
type HeadlessAgentHandle,
|
||||||
|
type HeadlessAgentOptions,
|
||||||
|
type HeadlessAgentResult,
|
||||||
|
type IHeadlessAgentRunner,
|
||||||
|
} from "./headless.js";
|
||||||
|
|
||||||
|
function runner(): IHeadlessAgentRunner {
|
||||||
|
return container.resolve<IHeadlessAgentRunner>("headlessAgentRunner");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function startHeadlessAgent(
|
||||||
|
options: HeadlessAgentOptions,
|
||||||
|
): Promise<HeadlessAgentHandle> {
|
||||||
|
return runner().start(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runHeadlessAgent(
|
||||||
|
options: HeadlessAgentOptions,
|
||||||
|
): Promise<HeadlessAgentResult & { turnId: string }> {
|
||||||
|
return runner().run(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolInputPaths } from "./headless.js";
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
import { reduceTurn, type TurnEvent } from "@x/shared/dist/turns.js";
|
import { reduceTurn, type TurnEvent } from "@x/shared/dist/turns.js";
|
||||||
import type {
|
import type {
|
||||||
|
|
@ -9,11 +9,12 @@ import type {
|
||||||
} from "../turns/api.js";
|
} from "../turns/api.js";
|
||||||
import {
|
import {
|
||||||
HeadlessRunError,
|
HeadlessRunError,
|
||||||
|
HeadlessAgentRunner,
|
||||||
assistantText,
|
assistantText,
|
||||||
lastAssistantText,
|
lastAssistantText,
|
||||||
startHeadlessAgent,
|
|
||||||
toolInputPaths,
|
toolInputPaths,
|
||||||
} from "./headless.js";
|
} from "./headless.js";
|
||||||
|
import type { IDefaultModelResolver } from "../models/default-model-resolver.js";
|
||||||
|
|
||||||
type TEvent = z.infer<typeof TurnEvent>;
|
type TEvent = z.infer<typeof TurnEvent>;
|
||||||
|
|
||||||
|
|
@ -166,6 +167,22 @@ const completedOutcome: TurnOutcome = {
|
||||||
usage: {},
|
usage: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function createRunner(
|
||||||
|
runtime: ITurnRuntime,
|
||||||
|
resolve = vi.fn(async () => ({
|
||||||
|
provider: "default-provider",
|
||||||
|
model: "default-model",
|
||||||
|
})),
|
||||||
|
): { runner: HeadlessAgentRunner; resolve: IDefaultModelResolver["resolve"] } {
|
||||||
|
return {
|
||||||
|
runner: new HeadlessAgentRunner({
|
||||||
|
turnRuntime: runtime,
|
||||||
|
defaultModelResolver: { resolve },
|
||||||
|
}),
|
||||||
|
resolve,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
describe("headless agent helpers", () => {
|
describe("headless agent helpers", () => {
|
||||||
it("assistantText handles string and parts content", () => {
|
it("assistantText handles string and parts content", () => {
|
||||||
expect(assistantText({ role: "assistant", content: "hi" })).toBe("hi");
|
expect(assistantText({ role: "assistant", content: "hi" })).toBe("hi");
|
||||||
|
|
@ -206,14 +223,18 @@ describe("headless agent helpers", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("startHeadlessAgent", () => {
|
describe("HeadlessAgentRunner", () => {
|
||||||
it("creates a standalone auto-permission turn and returns the id before settling", async () => {
|
it("creates a standalone auto-permission turn and returns the id before settling", async () => {
|
||||||
const runtime = new FakeRuntime(turnLog({ responseText: "the summary" }), completedOutcome);
|
const runtime = new FakeRuntime(turnLog({ responseText: "the summary" }), completedOutcome);
|
||||||
const handle = await startHeadlessAgent(
|
const { runner, resolve } = createRunner(runtime);
|
||||||
{ agentId: "worker", message: "go", model: "m", provider: "fake" },
|
const handle = await runner.start({
|
||||||
runtime,
|
agentId: "worker",
|
||||||
);
|
message: "go",
|
||||||
|
model: "m",
|
||||||
|
provider: "fake",
|
||||||
|
});
|
||||||
expect(handle.turnId).toBe(TURN_ID);
|
expect(handle.turnId).toBe(TURN_ID);
|
||||||
|
expect(resolve).not.toHaveBeenCalled();
|
||||||
expect(runtime.createInputs[0]).toMatchObject({
|
expect(runtime.createInputs[0]).toMatchObject({
|
||||||
agent: { agentId: "worker", overrides: { model: { provider: "fake", model: "m" } } },
|
agent: { agentId: "worker", overrides: { model: { provider: "fake", model: "m" } } },
|
||||||
sessionId: null,
|
sessionId: null,
|
||||||
|
|
@ -228,20 +249,38 @@ describe("startHeadlessAgent", () => {
|
||||||
|
|
||||||
it("omits the model override when neither model nor provider is set", async () => {
|
it("omits the model override when neither model nor provider is set", async () => {
|
||||||
const runtime = new FakeRuntime(turnLog({ responseText: "ok" }), completedOutcome);
|
const runtime = new FakeRuntime(turnLog({ responseText: "ok" }), completedOutcome);
|
||||||
await startHeadlessAgent({ agentId: "worker", message: "go" }, runtime);
|
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.overrides).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses an injected default only for a partial model override", async () => {
|
||||||
|
const runtime = new FakeRuntime(turnLog({ responseText: "ok" }), completedOutcome);
|
||||||
|
const { runner, resolve } = createRunner(runtime);
|
||||||
|
await runner.start({
|
||||||
|
agentId: "worker",
|
||||||
|
message: "go",
|
||||||
|
model: "custom-model",
|
||||||
|
});
|
||||||
|
expect(resolve).toHaveBeenCalledOnce();
|
||||||
|
expect(runtime.createInputs[0].agent.overrides).toEqual({
|
||||||
|
model: { provider: "default-provider", model: "custom-model" },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("throwOnError rejects done with HeadlessRunError on failed outcomes", async () => {
|
it("throwOnError rejects done with HeadlessRunError on failed outcomes", async () => {
|
||||||
const runtime = new FakeRuntime(turnLog({ failed: "provider exploded" }), {
|
const runtime = new FakeRuntime(turnLog({ failed: "provider exploded" }), {
|
||||||
status: "failed",
|
status: "failed",
|
||||||
error: "provider exploded",
|
error: "provider exploded",
|
||||||
usage: {},
|
usage: {},
|
||||||
});
|
});
|
||||||
const handle = await startHeadlessAgent(
|
const { runner } = createRunner(runtime);
|
||||||
{ agentId: "worker", message: "go", throwOnError: true },
|
const handle = await runner.start({
|
||||||
runtime,
|
agentId: "worker",
|
||||||
);
|
message: "go",
|
||||||
|
throwOnError: true,
|
||||||
|
});
|
||||||
await expect(handle.done).rejects.toThrowError(HeadlessRunError);
|
await expect(handle.done).rejects.toThrowError(HeadlessRunError);
|
||||||
await expect(handle.done).rejects.toThrowError("provider exploded");
|
await expect(handle.done).rejects.toThrowError("provider exploded");
|
||||||
});
|
});
|
||||||
|
|
@ -252,7 +291,8 @@ describe("startHeadlessAgent", () => {
|
||||||
error: "boom",
|
error: "boom",
|
||||||
usage: {},
|
usage: {},
|
||||||
});
|
});
|
||||||
const handle = await startHeadlessAgent({ agentId: "worker", message: "go" }, runtime);
|
const { runner } = createRunner(runtime);
|
||||||
|
const handle = await runner.start({ agentId: "worker", message: "go" });
|
||||||
const result = await handle.done;
|
const result = await handle.done;
|
||||||
expect(result.outcome.status).toBe("failed");
|
expect(result.outcome.status).toBe("failed");
|
||||||
expect(result.summary).toBeNull();
|
expect(result.summary).toBeNull();
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,13 @@ import {
|
||||||
reduceTurn,
|
reduceTurn,
|
||||||
type TurnState,
|
type TurnState,
|
||||||
} from "@x/shared/dist/turns.js";
|
} from "@x/shared/dist/turns.js";
|
||||||
import container from "../di/container.js";
|
|
||||||
import { getDefaultModelAndProvider } from "../models/defaults.js";
|
|
||||||
import type { ITurnRuntime, TurnOutcome } from "../turns/api.js";
|
import type { ITurnRuntime, TurnOutcome } from "../turns/api.js";
|
||||||
|
import type { IDefaultModelResolver } from "../models/default-model-resolver.js";
|
||||||
|
|
||||||
// Drop-in replacement for the old headless runs pattern
|
// Drop-in replacement for the old headless runs pattern
|
||||||
// (createRun → createMessage → waitForRunCompletion → extractAgentResponse):
|
// (createRun → createMessage → waitForRunCompletion → extractAgentResponse):
|
||||||
// one standalone turn per invocation (sessionId null, automatic permissions,
|
// one standalone turn per invocation (sessionId null, automatic permissions,
|
||||||
// no human). startHeadlessAgent returns the turn id immediately (callers
|
// no human). HeadlessAgentRunner.start returns the turn id immediately (callers
|
||||||
// record it in pointer files / bus events before completion); `done` settles
|
// record it in pointer files / bus events before completion); `done` settles
|
||||||
// with the outcome, the reduced turn state, and the final assistant text.
|
// with the outcome, the reduced turn state, and the final assistant text.
|
||||||
|
|
||||||
|
|
@ -51,6 +50,18 @@ export interface HeadlessAgentHandle {
|
||||||
done: Promise<HeadlessAgentResult>;
|
done: Promise<HeadlessAgentResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HeadlessAgentRunnerDependencies {
|
||||||
|
turnRuntime: ITurnRuntime;
|
||||||
|
defaultModelResolver: IDefaultModelResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IHeadlessAgentRunner {
|
||||||
|
start(options: HeadlessAgentOptions): Promise<HeadlessAgentHandle>;
|
||||||
|
run(
|
||||||
|
options: HeadlessAgentOptions,
|
||||||
|
): Promise<HeadlessAgentResult & { turnId: string }>;
|
||||||
|
}
|
||||||
|
|
||||||
export function assistantText(
|
export function assistantText(
|
||||||
message: z.infer<typeof AssistantMessage>,
|
message: z.infer<typeof AssistantMessage>,
|
||||||
): string | null {
|
): string | null {
|
||||||
|
|
@ -97,63 +108,75 @@ export function toolInputPaths(
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function startHeadlessAgent(
|
export class HeadlessAgentRunner implements IHeadlessAgentRunner {
|
||||||
options: HeadlessAgentOptions,
|
private readonly turnRuntime: ITurnRuntime;
|
||||||
// Injectable for tests; defaults to the app container's runtime.
|
private readonly defaultModelResolver: IDefaultModelResolver;
|
||||||
turnRuntime: ITurnRuntime = container.resolve<ITurnRuntime>("turnRuntime"),
|
|
||||||
): Promise<HeadlessAgentHandle> {
|
constructor({
|
||||||
let modelOverride: { provider: string; model: string } | undefined;
|
turnRuntime,
|
||||||
if (options.model || options.provider) {
|
defaultModelResolver,
|
||||||
const defaults = await getDefaultModelAndProvider();
|
}: HeadlessAgentRunnerDependencies) {
|
||||||
modelOverride = {
|
this.turnRuntime = turnRuntime;
|
||||||
provider: options.provider ?? defaults.provider,
|
this.defaultModelResolver = defaultModelResolver;
|
||||||
model: options.model ?? defaults.model,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const turnId = await turnRuntime.createTurn({
|
async start(options: HeadlessAgentOptions): Promise<HeadlessAgentHandle> {
|
||||||
agent: {
|
let modelOverride: { provider: string; model: string } | undefined;
|
||||||
agentId: options.agentId,
|
if (options.model && options.provider) {
|
||||||
...(modelOverride ? { overrides: { model: modelOverride } } : {}),
|
modelOverride = { provider: options.provider, model: options.model };
|
||||||
},
|
} else if (options.model || options.provider) {
|
||||||
sessionId: null,
|
const defaults = await this.defaultModelResolver.resolve();
|
||||||
context: [],
|
modelOverride = {
|
||||||
input: { role: "user", content: options.message },
|
provider: options.provider ?? defaults.provider,
|
||||||
config: {
|
model: options.model ?? defaults.model,
|
||||||
autoPermission: true,
|
};
|
||||||
humanAvailable: false,
|
|
||||||
...(options.maxModelCalls === undefined
|
|
||||||
? {}
|
|
||||||
: { maxModelCalls: options.maxModelCalls }),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const execution = turnRuntime.advanceTurn(turnId, undefined, {
|
|
||||||
signal: options.signal,
|
|
||||||
});
|
|
||||||
const done = execution.outcome.then(async (outcome) => {
|
|
||||||
const state = reduceTurn((await turnRuntime.getTurn(turnId)).events);
|
|
||||||
if (options.throwOnError && outcome.status !== "completed") {
|
|
||||||
throw new HeadlessRunError(
|
|
||||||
outcome.status === "failed"
|
|
||||||
? outcome.error
|
|
||||||
: `turn ${outcome.status}`,
|
|
||||||
turnId,
|
|
||||||
outcome,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return { outcome, state, summary: lastAssistantText(state) };
|
|
||||||
});
|
|
||||||
// The handle may be used fire-and-forget; rejections surface when awaited.
|
|
||||||
done.catch(() => undefined);
|
|
||||||
return { turnId, done };
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function runHeadlessAgent(
|
const turnId = await this.turnRuntime.createTurn({
|
||||||
options: HeadlessAgentOptions,
|
agent: {
|
||||||
turnRuntime?: ITurnRuntime,
|
agentId: options.agentId,
|
||||||
): Promise<HeadlessAgentResult & { turnId: string }> {
|
...(modelOverride ? { overrides: { model: modelOverride } } : {}),
|
||||||
const handle = await startHeadlessAgent(options, turnRuntime);
|
},
|
||||||
const result = await handle.done;
|
sessionId: null,
|
||||||
return { turnId: handle.turnId, ...result };
|
context: [],
|
||||||
|
input: { role: "user", content: options.message },
|
||||||
|
config: {
|
||||||
|
autoPermission: true,
|
||||||
|
humanAvailable: false,
|
||||||
|
...(options.maxModelCalls === undefined
|
||||||
|
? {}
|
||||||
|
: { maxModelCalls: options.maxModelCalls }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const execution = this.turnRuntime.advanceTurn(turnId, undefined, {
|
||||||
|
signal: options.signal,
|
||||||
|
});
|
||||||
|
const done = execution.outcome.then(async (outcome) => {
|
||||||
|
const state = reduceTurn(
|
||||||
|
(await this.turnRuntime.getTurn(turnId)).events,
|
||||||
|
);
|
||||||
|
if (options.throwOnError && outcome.status !== "completed") {
|
||||||
|
throw new HeadlessRunError(
|
||||||
|
outcome.status === "failed"
|
||||||
|
? outcome.error
|
||||||
|
: `turn ${outcome.status}`,
|
||||||
|
turnId,
|
||||||
|
outcome,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return { outcome, state, summary: lastAssistantText(state) };
|
||||||
|
});
|
||||||
|
// The handle may be used fire-and-forget; rejections surface when awaited.
|
||||||
|
done.catch(() => undefined);
|
||||||
|
return { turnId, done };
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(
|
||||||
|
options: HeadlessAgentOptions,
|
||||||
|
): Promise<HeadlessAgentResult & { turnId: string }> {
|
||||||
|
const handle = await this.start(options);
|
||||||
|
const result = await handle.done;
|
||||||
|
return { turnId: handle.turnId, ...result };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import type { BackgroundTask, BackgroundTaskTriggerType } from '@x/shared/dist/b
|
||||||
import { PrefixLogger } from '@x/shared/dist/prefix-logger.js';
|
import { PrefixLogger } from '@x/shared/dist/prefix-logger.js';
|
||||||
import { fetchTask, patchTask, prependRunId } from './fileops.js';
|
import { fetchTask, patchTask, prependRunId } from './fileops.js';
|
||||||
import { getBackgroundTaskAgentModel } from '../models/defaults.js';
|
import { getBackgroundTaskAgentModel } from '../models/defaults.js';
|
||||||
import { startHeadlessAgent } from '../agents/headless.js';
|
import { startHeadlessAgent } from '../agents/headless-app.js';
|
||||||
import { buildTriggerBlock } from '../agents/build-trigger-block.js';
|
import { buildTriggerBlock } from '../agents/build-trigger-block.js';
|
||||||
import { backgroundTaskBus } from './bus.js';
|
import { backgroundTaskBus } from './bus.js';
|
||||||
import { withUseCase } from '../analytics/use_case.js';
|
import { withUseCase } from '../analytics/use_case.js';
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,14 @@ import type { ISessionRepo } from "../sessions/repo.js";
|
||||||
import { EmitterSessionBus, type ISessionBus } from "../sessions/bus.js";
|
import { EmitterSessionBus, type ISessionBus } from "../sessions/bus.js";
|
||||||
import { SessionsImpl } from "../sessions/sessions.js";
|
import { SessionsImpl } from "../sessions/sessions.js";
|
||||||
import type { ISessions } from "../sessions/api.js";
|
import type { ISessions } from "../sessions/api.js";
|
||||||
|
import {
|
||||||
|
DefaultModelResolver,
|
||||||
|
type IDefaultModelResolver,
|
||||||
|
} from "../models/default-model-resolver.js";
|
||||||
|
import {
|
||||||
|
HeadlessAgentRunner,
|
||||||
|
type IHeadlessAgentRunner,
|
||||||
|
} from "../agents/headless.js";
|
||||||
|
|
||||||
const container = createContainer({
|
const container = createContainer({
|
||||||
injectionMode: InjectionMode.PROXY,
|
injectionMode: InjectionMode.PROXY,
|
||||||
|
|
@ -115,6 +123,10 @@ container.register({
|
||||||
sessionRepo: asClass<ISessionRepo>(FSSessionRepo).singleton(),
|
sessionRepo: asClass<ISessionRepo>(FSSessionRepo).singleton(),
|
||||||
sessionBus: asClass<ISessionBus>(EmitterSessionBus).singleton(),
|
sessionBus: asClass<ISessionBus>(EmitterSessionBus).singleton(),
|
||||||
sessions: asClass<ISessions>(SessionsImpl).singleton(),
|
sessions: asClass<ISessions>(SessionsImpl).singleton(),
|
||||||
|
defaultModelResolver:
|
||||||
|
asClass<IDefaultModelResolver>(DefaultModelResolver).singleton(),
|
||||||
|
headlessAgentRunner:
|
||||||
|
asClass<IHeadlessAgentRunner>(HeadlessAgentRunner).singleton(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default container;
|
export default container;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { google } from 'googleapis';
|
import { google } from 'googleapis';
|
||||||
import { WorkDir } from '../config/config.js';
|
import { WorkDir } from '../config/config.js';
|
||||||
import { runHeadlessAgent } from '../agents/headless.js';
|
import { runHeadlessAgent } from '../agents/headless-app.js';
|
||||||
import { getKgModel } from '../models/defaults.js';
|
import { getKgModel } from '../models/defaults.js';
|
||||||
import { getErrorDetails } from '../agents/utils.js';
|
import { getErrorDetails } from '../agents/utils.js';
|
||||||
import { serviceLogger } from '../services/service_logger.js';
|
import { serviceLogger } from '../services/service_logger.js';
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { WorkDir } from '../config/config.js';
|
import { WorkDir } from '../config/config.js';
|
||||||
import { getKgModel } from '../models/defaults.js';
|
import { getKgModel } from '../models/defaults.js';
|
||||||
import { runHeadlessAgent, toolInputPaths } from '../agents/headless.js';
|
import { runHeadlessAgent, toolInputPaths } from '../agents/headless-app.js';
|
||||||
import { getErrorDetails } from '../agents/utils.js';
|
import { getErrorDetails } from '../agents/utils.js';
|
||||||
import { serviceLogger, type ServiceRunContext } from '../services/service_logger.js';
|
import { serviceLogger, type ServiceRunContext } from '../services/service_logger.js';
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import path from 'path';
|
||||||
import { CronExpressionParser } from 'cron-parser';
|
import { CronExpressionParser } from 'cron-parser';
|
||||||
import { generateText } from 'ai';
|
import { generateText } from 'ai';
|
||||||
import { WorkDir } from '../config/config.js';
|
import { WorkDir } from '../config/config.js';
|
||||||
import { runHeadlessAgent } from '../agents/headless.js';
|
import { runHeadlessAgent } from '../agents/headless-app.js';
|
||||||
import { getKgModel } from '../models/defaults.js';
|
import { getKgModel } from '../models/defaults.js';
|
||||||
import container from '../di/container.js';
|
import container from '../di/container.js';
|
||||||
import type { IModelConfigRepo } from '../models/repo.js';
|
import type { IModelConfigRepo } from '../models/repo.js';
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { WorkDir } from '../config/config.js';
|
import { WorkDir } from '../config/config.js';
|
||||||
import { runHeadlessAgent, toolInputPaths } from '../agents/headless.js';
|
import { runHeadlessAgent, toolInputPaths } from '../agents/headless-app.js';
|
||||||
import { getKgModel } from '../models/defaults.js';
|
import { getKgModel } from '../models/defaults.js';
|
||||||
import { getErrorDetails } from '../agents/utils.js';
|
import { getErrorDetails } from '../agents/utils.js';
|
||||||
import { serviceLogger } from '../services/service_logger.js';
|
import { serviceLogger } from '../services/service_logger.js';
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import type { LiveNote, LiveNoteTriggerType } from '@x/shared/dist/live-note.js';
|
import type { LiveNote, LiveNoteTriggerType } from '@x/shared/dist/live-note.js';
|
||||||
import { fetchLiveNote, patchLiveNote, readNoteBody } from './fileops.js';
|
import { fetchLiveNote, patchLiveNote, readNoteBody } from './fileops.js';
|
||||||
import { getLiveNoteAgentModel } from '../../models/defaults.js';
|
import { getLiveNoteAgentModel } from '../../models/defaults.js';
|
||||||
import { startHeadlessAgent } from '../../agents/headless.js';
|
import { startHeadlessAgent } from '../../agents/headless-app.js';
|
||||||
import { withUseCase } from '../../analytics/use_case.js';
|
import { withUseCase } from '../../analytics/use_case.js';
|
||||||
import { buildTriggerBlock } from '../../agents/build-trigger-block.js';
|
import { buildTriggerBlock } from '../../agents/build-trigger-block.js';
|
||||||
import { liveNoteBus } from './bus.js';
|
import { liveNoteBus } from './bus.js';
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { WorkDir } from '../config/config.js';
|
import { WorkDir } from '../config/config.js';
|
||||||
import { runHeadlessAgent, toolInputPaths } from '../agents/headless.js';
|
import { runHeadlessAgent, toolInputPaths } from '../agents/headless-app.js';
|
||||||
import { getKgModel } from '../models/defaults.js';
|
import { getKgModel } from '../models/defaults.js';
|
||||||
import { getErrorDetails } from '../agents/utils.js';
|
import { getErrorDetails } from '../agents/utils.js';
|
||||||
import { serviceLogger } from '../services/service_logger.js';
|
import { serviceLogger } from '../services/service_logger.js';
|
||||||
|
|
|
||||||
11
apps/x/packages/core/src/models/default-model-resolver.ts
Normal file
11
apps/x/packages/core/src/models/default-model-resolver.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { getDefaultModelAndProvider } from "./defaults.js";
|
||||||
|
|
||||||
|
export interface IDefaultModelResolver {
|
||||||
|
resolve(): Promise<{ model: string; provider: string }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DefaultModelResolver implements IDefaultModelResolver {
|
||||||
|
resolve(): Promise<{ model: string; provider: string }> {
|
||||||
|
return getDefaultModelAndProvider();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { WorkDir } from '../config/config.js';
|
import { WorkDir } from '../config/config.js';
|
||||||
import { runHeadlessAgent } from '../agents/headless.js';
|
import { runHeadlessAgent } from '../agents/headless-app.js';
|
||||||
import { getKgModel } from '../models/defaults.js';
|
import { getKgModel } from '../models/defaults.js';
|
||||||
import {
|
import {
|
||||||
loadConfig,
|
loadConfig,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue