Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/core/src/agent/heartbeat-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,15 @@ export class HeartbeatProcessor {
}
}

/**
* Convert a value to a string suitable for templates.
*
* If `obj` is already a string it is returned unchanged; otherwise the value
* is serialized with `JSON.stringify`.
*
* @param obj - Value to convert (string or any JSON-serializable value)
* @returns A string representation of `obj`
*/
function _toString(obj) {
if (typeof obj === "string") return obj;
return JSON.stringify(obj);
Expand Down
45 changes: 45 additions & 0 deletions packages/core/src/config/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ import semver from "semver";
import { ConfigV201 } from "./versions/v201";
import { ModelAbility, ModelDescriptor } from "@/services";

/**
* Migrate a v1 configuration object to the v2.0.0 configuration shape.
*
* Produces a new config with version "2.0.0" by:
* - copying top-level service sections (modelService, assetService, promptService, system),
* - flattening nested agentBehavior fields (arousal, willingness, vision, prompt) into the top level,
* - setting `enableVision` from `vision?.enabled`,
* - carrying selected agentBehavior flags (streamAction, heartbeat, newMessageStrategy, deferredProcessingTime),
* - flattening capabilities (history, memory, tools) into the top level,
* - mapping `assetEndpoint` from `assetService.endpoint`.
*
* @param configV1 - The original configuration in the 1.0.0 shape to migrate.
* @returns A config object shaped as v2.0.0 (omitting `enableTelemetry` and `sentryDsn`).
*/
function migrateV1ToV200(configV1: ConfigV1): Omit<ConfigV200, "enableTelemetry" | "sentryDsn"> {
const { modelService, agentBehavior, capabilities, assetService, promptService, system } = configV1;

Expand Down Expand Up @@ -39,13 +53,33 @@ function migrateV1ToV200(configV1: ConfigV1): Omit<ConfigV200, "enableTelemetry"
};
}

/**
* Migrate a 2.0.0 config object to the 2.0.1 shape by preserving all fields and updating the version.
*
* @param configV200 - Configuration object with version "2.0.0"
* @returns The same configuration adjusted to version "2.0.1"
*/
function migrateV200ToV201(configV200: ConfigV200): ConfigV201 {
return {
...configV200,
version: "2.0.1",
};
}

/**
* Migrates a v2.0.1 configuration to the v2.0.2 shape.
*
* Produces a new Config with:
* - chatModelGroup set from `task.chat`
* - embeddingModel taken from the first model of the model group named by `task.embed` (both `providerName` and `modelId` default to empty strings if not found)
* - ignoreCommandMessage set to `false`
* - version set to `"2.0.2"`
*
* The function does not mutate the input; it clones the input before reading. The rest of the configuration fields are preserved unchanged.
*
* @param configV201 - Configuration object in the v2.0.1 shape to migrate
* @returns The migrated configuration in the v2.0.2 shape
*/
function migrateV201ToV202(configV201: ConfigV201): Config {
configV201 = structuredClone(configV201);

Expand Down Expand Up @@ -77,6 +111,17 @@ const MIGRATIONS = {
"2.0.1": migrateV201ToV202,
};

/**
* Migrate an arbitrary configuration object forward to the current CONFIG_VERSION.
*
* Repeatedly applies versioned migration functions until the config reaches the latest version.
*
* @param config - A configuration object of any (possibly older) schema version. The object must include a `version` field indicating its current semantic version.
* @returns The migrated configuration shaped as the current `Config` type and annotated with the latest `version`.
*
* @throws Error If a required migration step is missing for a detected intermediate version.
* @throws Error If a migration function returns a config without a `version` field.
*/
export function migrateConfig(config: any): Config {
let migratedConfig = { ...config };
let currentVersion = String(migratedConfig.version);
Expand Down
14 changes: 11 additions & 3 deletions packages/core/src/services/extension/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,17 @@ import { ExtensionMetadata, Infer, ToolDefinition, ToolMetadata } from "./types"
type Constructor<T = {}> = new (...args: any[]) => T;

/**
* @Extension 类装饰器
* 将一个普通类转换为功能完备、可被 Koishi 直接加载的工具扩展插件。
* @param metadata 扩展包的元数据对象
* Class decorator that turns a plain class into a Koishi-loadable tool extension.
*
* The decorator wraps the target class to perform automatic runtime registration with the tool
* management service: it binds per-instance tool `execute` methods, registers the extension
* on the Koishi `ready` event (using the instance config `enabled` flag), and unregisters it
* on `dispose`. It also attaches the provided metadata to the wrapped prototype, preserves a
* static `Config` if present, sets the wrapped class name to `metadata.name`, and ensures the
* wrapped class declares the tool and logger services in its `inject` metadata.
*
* @param metadata - Extension package metadata used for registration (provides the extension name and related info)
* @returns A class decorator that produces a wrapped extension class compatible with Koishi's tool service
*/
export function Extension(metadata: ExtensionMetadata): ClassDecorator {
//@ts-ignore
Expand Down