Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

573 lines
18 KiB
TypeScript

// Canonical tuttid DTO-to-activity composer-options mapper.
import type {
AgentActivityComposerCapabilityOption,
AgentActivityComposerOptions,
AgentActivityComposerPermissionConfig,
AgentActivityComposerSettingOption,
AgentActivityComposerSkillOption,
AgentActivitySessionCapabilities,
AgentActivitySlashCommandEffect,
AgentActivitySlashCommandPolicy
} from "@tutti-os/agent-activity-core";
import type { AgentProviderComposerOptionsResponse } from "@tutti-os/client-tuttid-ts";
export function agentActivityComposerOptionsFromTuttidResult(
provider: string,
value: AgentProviderComposerOptionsResponse
): AgentActivityComposerOptions {
const result = recordValue(value);
const runtimeContext = recordValue(result.runtimeContext);
const modelConfig = recordValue(result.modelConfig);
const reasoningConfig = recordValue(result.reasoningConfig);
const speedConfig = recordValue(result.speedConfig);
const effectiveSettings = composerSettingsFromValue(result.effectiveSettings);
const modelsFromConfig = settingOptionsFromComposerConfig(modelConfig);
const reasoningEffortsFromConfig =
settingOptionsFromComposerConfig(reasoningConfig);
const speedsFromConfig = settingOptionsFromComposerConfig(speedConfig);
const skillsFromResult = skillOptionsFromValue(result.skills);
const capabilityCatalog = capabilityOptionsFromValue(
result.capabilityCatalog
);
return {
codexSaverModeSupported: result.codexSaverModeSupported === true,
rtkSaverModeSupported: result.rtkSaverModeSupported === true,
provider: normalizeText(result.provider) ?? provider,
capabilities: sessionCapabilitiesFromValue(result.capabilities),
models: modelsFromConfig,
reasoningEfforts: reasoningEffortsFromConfig,
reasoningOptionsByModel: reasoningOptionsByModelFromValue(
result.reasoningOptionsByModel
),
speeds: speedsFromConfig,
modelConfigurable: modelConfig.configurable === true,
effectiveModel: normalizeText(modelConfig.effectiveValue),
reasoningConfigurable: reasoningConfig.configurable === true,
speedConfigurable: speedConfig.configurable === true,
effectiveSettings,
permissionConfig: permissionConfigFromValue(result.permissionConfig),
draftAgentSessionId: normalizeText(runtimeContext.draftAgentSessionId),
modelOptionsLoading:
recordValue(runtimeContext.appServerStartup).models === "loading",
skills: skillsFromResult,
commands: commandOptionsFromValue(result.commands),
capabilityCatalog,
behavior: composerBehaviorFromValue(result.behavior),
slashCommandPolicy: slashCommandPolicyFromValue(result.slashCommandPolicy),
modelPlan: composerModelPlanFromValue(runtimeContext.modelPlan),
modelConfiguration: composerModelConfigurationFromValue(
runtimeContext.modelConfiguration
),
loadedAtUnixMs: Date.now()
};
}
function commandOptionsFromValue(value: unknown) {
if (!Array.isArray(value)) return [];
const commands: Array<{
name: string;
description?: string;
inputHint?: string;
}> = [];
const seen = new Set<string>();
for (const raw of value) {
const command = recordValue(raw);
const name = normalizeText(command.name);
if (!name || seen.has(name)) continue;
seen.add(name);
const description = normalizeText(command.description);
const inputHint = normalizeText(command.inputHint);
commands.push({
name,
...(description ? { description } : {}),
...(inputHint ? { inputHint } : {})
});
}
return commands;
}
function composerModelPlanFromValue(
value: unknown
): AgentActivityComposerOptions["modelPlan"] {
const plan = recordValue(value);
const id = normalizeText(plan.id);
const name = normalizeText(plan.name);
if (!id || !name) {
return null;
}
return {
id,
name,
protocol: normalizeText(plan.protocol)
};
}
function composerModelConfigurationFromValue(
value: unknown
): AgentActivityComposerOptions["modelConfiguration"] {
const configuration = recordValue(value);
const agentTargetId = normalizeText(configuration.agentTargetId);
const fingerprint = normalizeText(configuration.fingerprint);
const source = normalizeText(configuration.source);
if (
!agentTargetId ||
!fingerprint ||
(source !== "model-plan" && source !== "provider-native")
) {
return null;
}
return {
agentTargetId,
defaultModel: normalizeText(configuration.defaultModel) ?? null,
fingerprint,
source
};
}
function sessionCapabilitiesFromValue(
value: unknown
): AgentActivitySessionCapabilities | null {
const capabilities = recordValue(value);
if (Object.keys(capabilities).length === 0) {
return null;
}
return {
activeTurnGuidance: capabilities.activeTurnGuidance === true,
browserUse: capabilities.browserUse === true,
compact: capabilities.compact === true,
computerUse: capabilities.computerUse === true,
goalPause: capabilities.goalPause === true,
imageInput: capabilities.imageInput === true,
interrupt: capabilities.interrupt === true,
modelImageInputRequired: capabilities.modelImageInputRequired === true,
modelPlanBinding: capabilities.modelPlanBinding === true,
modelSwitch: capabilities.modelSwitch === true,
permissionModeChangeDeferred:
capabilities.permissionModeChangeDeferred === true,
permissionModeChangeDuringTurn:
capabilities.permissionModeChangeDuringTurn === true,
planImplementation: capabilities.planImplementation === true,
planMode: capabilities.planMode === true,
rateLimits: capabilities.rateLimits === true,
resumeRunningTurn: capabilities.resumeRunningTurn === true,
review: capabilities.review === true,
skills: capabilities.skills === true,
tokenUsage: capabilities.tokenUsage === true
};
}
function reasoningOptionsByModelFromValue(
value: unknown
): AgentActivityComposerOptions["reasoningOptionsByModel"] {
const profiles = recordValue(value);
const entries = Object.entries(profiles).flatMap(([model, rawProfile]) => {
const profile = recordValue(rawProfile);
const options = settingOptionsFromRawOptions(profile.options, {
labelKeys: ["name", "label", "displayName"],
valueKeys: ["value", "id"]
});
if (!model.trim()) {
return [];
}
return [
[
model.trim(),
{
defaultValue: normalizeText(profile.defaultValue),
options
}
] as const
];
});
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
}
function composerBehaviorFromValue(
value: unknown
): AgentActivityComposerOptions["behavior"] {
const behavior = recordValue(value);
return {
collapseModelOptionsToLatest:
behavior.collapseModelOptionsToLatest === true,
modelOptionsAuthoritative: behavior.modelOptionsAuthoritative === true,
refreshModelOptionsAfterSettings:
behavior.refreshModelOptionsAfterSettings === true,
prewarmDraftSession: behavior.prewarmDraftSession === true,
planModeExclusiveWithPermissionMode:
behavior.planModeExclusiveWithPermissionMode === true
};
}
function composerSettingsFromValue(
value: unknown
): AgentActivityComposerOptions["effectiveSettings"] {
const settings = recordValue(value);
if (Object.keys(settings).length === 0) {
return null;
}
return {
...(typeof settings.codexSaverMode === "boolean"
? { codexSaverMode: settings.codexSaverMode }
: {}),
...(typeof settings.rtkSaverMode === "boolean"
? { rtkSaverMode: settings.rtkSaverMode }
: {}),
model: normalizeText(settings.model),
reasoningEffort: normalizeText(settings.reasoningEffort),
speed: normalizeText(settings.speed),
planMode:
typeof settings.planMode === "boolean" ? settings.planMode : undefined,
permissionModeId: normalizeText(settings.permissionModeId)
};
}
function slashCommandPolicyFromValue(
value: unknown
): AgentActivitySlashCommandPolicy | null {
const policy = recordValue(value);
if (!Array.isArray(policy.fallbackCommands)) {
return null;
}
const fallbackCommands = policy.fallbackCommands.flatMap((entry) => {
const command = normalizeText(entry);
return command ? [command] : [];
});
const rawCommandEffects = Array.isArray(policy.commandEffects)
? policy.commandEffects
: [];
const commandEffects = rawCommandEffects.flatMap((entry) => {
const descriptor = recordValue(entry);
const command = normalizeText(descriptor.command);
const effect = slashCommandEffectFromValue(descriptor.effect);
return command && effect ? [{ command, effect }] : [];
});
return {
fallbackCommands,
commandEffects,
...(policy.commandCatalogAuthoritative === true
? { commandCatalogAuthoritative: true }
: {})
};
}
function slashCommandEffectFromValue(
value: unknown
): AgentActivitySlashCommandEffect | null {
switch (value) {
case "submitImmediate":
case "showReviewPicker":
case "activateGoalMode":
case "togglePlanMode":
case "showStatus":
case "toggleSpeed":
return value;
default:
return null;
}
}
function settingOptionsFromComposerConfig(
config: Record<string, unknown>
): AgentActivityComposerSettingOption[] {
const options = settingOptionsFromRawOptions(config.options, {
labelKeys: ["label", "name", "displayName"],
valueKeys: ["value", "id"]
});
const currentValue = normalizeText(
config.currentValue ?? config.current_value ?? config.defaultValue
);
return appendCurrentOption(options, currentValue);
}
function settingOptionsFromRawOptions(
value: unknown,
keys: {
labelKeys: readonly string[];
valueKeys: readonly string[];
}
): AgentActivityComposerSettingOption[] {
const options: AgentActivityComposerSettingOption[] = [];
const seen = new Set<string>();
for (const item of flattenRawSettingOptions(value)) {
const record = recordValue(item);
const optionValue = firstTextValue(record, keys.valueKeys);
if (!optionValue || seen.has(optionValue)) {
continue;
}
seen.add(optionValue);
const label = firstTextValue(record, keys.labelKeys) ?? optionValue;
const description = normalizeText(record.description);
const consumptionMultiplier = normalizeText(record.consumptionMultiplier);
const supportsImageInput =
typeof record.supportsImageInput === "boolean"
? record.supportsImageInput
: undefined;
options.push({
value: optionValue,
label,
...(description ? { description } : {}),
...(consumptionMultiplier ? { consumptionMultiplier } : {}),
...(supportsImageInput !== undefined ? { supportsImageInput } : {}),
// Daemon provenance: the entry mirrors the requested selection (warm
// catalog append / bootstrap echo) and is not catalog testimony.
...(record.requested === true ? { requested: true } : {})
});
}
return options;
}
function flattenRawSettingOptions(value: unknown): unknown[] {
if (!Array.isArray(value)) {
return [];
}
const flattened: unknown[] = [];
for (const item of value as unknown[]) {
const record = recordValue(item);
if (Array.isArray(record.options)) {
flattened.push(...flattenRawSettingOptions(record.options));
} else {
flattened.push(item);
}
}
return flattened;
}
function appendCurrentOption(
options: AgentActivityComposerSettingOption[],
currentValue: string | null
): AgentActivityComposerSettingOption[] {
if (
!currentValue ||
options.some((option) => option.value === currentValue)
) {
return options;
}
// This append mirrors the current selection so it stays selectable; mark
// it requested-origin — it is not evidence the provider catalog contains
// the model.
return [
...options,
{ value: currentValue, label: currentValue, requested: true }
];
}
function permissionConfigFromValue(
value: unknown
): AgentActivityComposerPermissionConfig | null {
const config = recordValue(value);
if (Object.keys(config).length === 0) {
return null;
}
const modes = Array.isArray(config.modes) ? config.modes : [];
const parsedModes: AgentActivityComposerPermissionConfig["modes"] = [];
for (const item of modes) {
const mode = recordValue(item);
const id = normalizeText(mode.id);
if (!id) {
continue;
}
const label = normalizeText(mode.label);
const description = normalizeText(mode.description);
const semantic = normalizeText(mode.semantic);
parsedModes.push({
id,
...(label ? { label } : {}),
...(description ? { description } : {}),
...(semantic ? { semantic } : {})
});
}
const defaultValue = normalizeText(
config.defaultValue ?? config.currentValue
);
return {
configurable: Boolean(config.configurable),
...(defaultValue ? { defaultValue } : {}),
modes: parsedModes
};
}
function skillOptionsFromValue(
value: unknown
): AgentActivityComposerSkillOption[] {
if (!Array.isArray(value)) {
return [];
}
const options: AgentActivityComposerSkillOption[] = [];
const seen = new Set<string>();
for (const item of value) {
const record = recordValue(item);
const name = normalizeText(record.name);
const trigger = normalizeText(record.trigger);
const sourceKind = normalizeSkillSourceKind(record.sourceKind);
if (!name || !trigger || !sourceKind || seen.has(trigger)) {
continue;
}
seen.add(trigger);
const description = normalizeText(record.description);
const pluginName = normalizeText(record.pluginName);
const path = normalizeText(record.path);
options.push({
name,
trigger,
sourceKind,
...(description ? { description } : {}),
...(pluginName ? { pluginName } : {}),
...(path ? { path } : {})
});
}
return options;
}
function normalizeSkillSourceKind(
value: unknown
): AgentActivityComposerSkillOption["sourceKind"] | null {
const normalized = normalizeText(value);
switch (normalized) {
case "project":
case "personal":
case "bundled":
case "plugin":
case "system":
case "tutti-injected":
return normalized;
default:
return null;
}
}
function capabilityOptionsFromValue(
value: unknown
): AgentActivityComposerCapabilityOption[] {
if (!Array.isArray(value)) {
return [];
}
const options: AgentActivityComposerCapabilityOption[] = [];
const seen = new Set<string>();
for (const item of value) {
const record = recordValue(item);
const id = normalizeText(record.id);
const kind = normalizeCapabilityKind(record.kind);
const name = normalizeText(record.name);
const label = normalizeText(record.label) ?? name;
const status = normalizeCapabilityStatus(record.status);
const invocation = normalizeCapabilityInvocation(record.invocation);
if (
!id ||
!kind ||
!name ||
!label ||
!status ||
!invocation ||
seen.has(id)
) {
continue;
}
seen.add(id);
const description = normalizeText(record.description);
const iconUrl = normalizeText(record.iconUrl);
const installedAtUnixMs = normalizePositiveInteger(
record.installedAtUnixMs
);
const source = normalizeText(record.source);
const pluginName = normalizeText(record.pluginName);
const serverName = normalizeText(record.serverName);
const toolName = normalizeText(record.toolName);
const trigger = normalizeText(record.trigger);
const path = normalizeText(record.path);
options.push({
id,
kind,
name,
label,
status,
invocation,
...(description ? { description } : {}),
...(iconUrl ? { iconUrl } : {}),
...(installedAtUnixMs ? { installedAtUnixMs } : {}),
...(source ? { source } : {}),
...(pluginName ? { pluginName } : {}),
...(serverName ? { serverName } : {}),
...(toolName ? { toolName } : {}),
...(trigger ? { trigger } : {}),
...(path ? { path } : {})
});
}
return options;
}
function normalizeCapabilityKind(
value: unknown
): AgentActivityComposerCapabilityOption["kind"] | null {
const normalized = normalizeText(value);
switch (normalized) {
case "skill":
case "plugin":
case "connector":
case "mcpServer":
case "mcpTool":
return normalized;
default:
return null;
}
}
function normalizeCapabilityStatus(
value: unknown
): AgentActivityComposerCapabilityOption["status"] | null {
const normalized = normalizeText(value);
switch (normalized) {
case "available":
case "disabled":
case "authRequired":
case "setupRequired":
case "unsupported":
return normalized;
default:
return null;
}
}
function normalizeCapabilityInvocation(
value: unknown
): AgentActivityComposerCapabilityOption["invocation"] | null {
const normalized = normalizeText(value);
switch (normalized) {
case "promptItem":
case "textTrigger":
case "none":
return normalized;
default:
return null;
}
}
function firstTextValue(
record: Record<string, unknown>,
keys: readonly string[]
): string | null {
for (const key of keys) {
const value = normalizeText(record[key]);
if (value) {
return value;
}
}
return null;
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function recordValue(value: unknown): Record<string, unknown> {
return isRecord(value) ? { ...value } : {};
}
function normalizeText(value: unknown): string | null {
return typeof value === "string" && value.trim() ? value.trim() : null;
}
function normalizePositiveInteger(value: unknown): number | null {
return typeof value === "number" && Number.isSafeInteger(value) && value > 0
? value
: null;
}