源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
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
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
This commit is contained in:
@@ -0,0 +1,567 @@
|
||||
import type { AgentSessionCommand } from "../../../shared/agentSessionTypes";
|
||||
import type {
|
||||
AgentActivityComposerOptions,
|
||||
AgentActivitySubmitSettingsPatch,
|
||||
AgentActivitySlashCommandPolicy
|
||||
} from "@tutti-os/agent-activity-core";
|
||||
import {
|
||||
agentCapabilityUseDisplayPrompt,
|
||||
buildAgentCapabilityUseSubmitPrompt,
|
||||
parseAgentCapabilityUseInvocation
|
||||
} from "./agentCapabilityUseSubmit";
|
||||
import type { AgentCapabilityUse } from "./agentCapabilityUseSubmit";
|
||||
import {
|
||||
draftForSlashCommand,
|
||||
mergeSlashCommands,
|
||||
parseSlashCommandInvocation,
|
||||
promptForSlashCommand
|
||||
} from "./agentSlashCommands";
|
||||
|
||||
export type AgentSlashCommandProvider = string;
|
||||
|
||||
export interface AgentSlashCommandCapability {
|
||||
aliases?: readonly string[];
|
||||
capability: AgentCapabilityUse | "tutti";
|
||||
kind: "capability";
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type AgentSlashCommand =
|
||||
| AgentSessionCommand
|
||||
| AgentSlashCommandCapability;
|
||||
|
||||
export type AgentSlashCommandPolicy = AgentActivitySlashCommandPolicy;
|
||||
|
||||
export type SlashCommandSelectionEffect =
|
||||
| {
|
||||
kind: "fillDraft";
|
||||
draft: string;
|
||||
}
|
||||
| {
|
||||
kind: "activateGoalMode";
|
||||
}
|
||||
| {
|
||||
kind: "submitPrompt";
|
||||
prompt: string;
|
||||
displayPrompt?: string;
|
||||
requiredSettingsPatch?: AgentActivitySubmitSettingsPatch;
|
||||
}
|
||||
| {
|
||||
kind: "showStatus";
|
||||
}
|
||||
| {
|
||||
kind: "enablePlanMode";
|
||||
}
|
||||
| {
|
||||
kind: "activateTuttiMode";
|
||||
}
|
||||
| {
|
||||
kind: "enableBrowserUse";
|
||||
draft: string;
|
||||
}
|
||||
| {
|
||||
kind: "enableComputerUse";
|
||||
draft: string;
|
||||
}
|
||||
| {
|
||||
kind: "showReviewPicker";
|
||||
}
|
||||
| {
|
||||
kind: "toggleSpeed";
|
||||
};
|
||||
|
||||
interface ResolveSlashCommandSelectionEffectInput {
|
||||
provider: AgentSlashCommandProvider;
|
||||
policy?: AgentSlashCommandPolicy | null;
|
||||
command: AgentSlashCommand;
|
||||
currentDraft: string;
|
||||
}
|
||||
|
||||
interface ResolveSlashCommandSubmitEffectInput {
|
||||
browserSupported?: boolean;
|
||||
computerSupported?: boolean;
|
||||
tuttiSupported?: boolean;
|
||||
provider: AgentSlashCommandProvider;
|
||||
policy?: AgentSlashCommandPolicy | null;
|
||||
commands: readonly AgentSlashCommand[];
|
||||
draft: string;
|
||||
}
|
||||
|
||||
interface ProviderSlashPolicy {
|
||||
/** Commands submitted immediately on selection instead of filling a draft. */
|
||||
immediateCommands: ReadonlySet<string>;
|
||||
/** Commands that open the shared review target picker when invoked bare. */
|
||||
reviewPickerCommands: ReadonlySet<string>;
|
||||
/** Commands surfaced when the agent advertises none of its own. */
|
||||
fallbackCommands: readonly AgentSessionCommand[];
|
||||
localGoalCommands: ReadonlySet<string>;
|
||||
localPlanCommands: ReadonlySet<string>;
|
||||
localStatusCommands: ReadonlySet<string>;
|
||||
localSpeedCommands: ReadonlySet<string>;
|
||||
}
|
||||
|
||||
// `/plan` enables plan mode locally (a negotiated capability) rather than
|
||||
// reaching the agent as a prompt; removing its badge disables it again.
|
||||
// `/fast` toggles the descriptor-advertised speed dimension locally.
|
||||
const BROWSER_USE_CAPABILITY_COMMAND: AgentSlashCommandCapability = {
|
||||
kind: "capability",
|
||||
capability: "browserUse",
|
||||
name: "browser",
|
||||
aliases: ["浏览器"]
|
||||
};
|
||||
const COMPUTER_USE_CAPABILITY_COMMAND: AgentSlashCommandCapability = {
|
||||
kind: "capability",
|
||||
capability: "computerUse",
|
||||
name: "computer",
|
||||
aliases: ["电脑"]
|
||||
};
|
||||
const TUTTI_CAPABILITY_COMMAND: AgentSlashCommandCapability = {
|
||||
kind: "capability",
|
||||
capability: "tutti",
|
||||
name: "tutti"
|
||||
};
|
||||
const PLAN_MODE_COMMAND: AgentSessionCommand = { name: "plan" };
|
||||
|
||||
function providerSlashPolicy(
|
||||
policy?: AgentSlashCommandPolicy | null
|
||||
): ProviderSlashPolicy | undefined {
|
||||
if (policy) {
|
||||
const commandEffects = Array.isArray(policy.commandEffects)
|
||||
? policy.commandEffects
|
||||
: [];
|
||||
const fallbackCommands = Array.isArray(policy.fallbackCommands)
|
||||
? policy.fallbackCommands
|
||||
: [];
|
||||
const commandsForEffect = (
|
||||
effect: AgentSlashCommandPolicy["commandEffects"][number]["effect"]
|
||||
) =>
|
||||
normalizedCommandSet(
|
||||
commandEffects.flatMap((entry) =>
|
||||
entry.effect === effect ? [entry.command] : []
|
||||
)
|
||||
);
|
||||
return {
|
||||
fallbackCommands: fallbackCommands.map((name) => ({ name })),
|
||||
immediateCommands: commandsForEffect("submitImmediate"),
|
||||
reviewPickerCommands: commandsForEffect("showReviewPicker"),
|
||||
localGoalCommands: commandsForEffect("activateGoalMode"),
|
||||
localPlanCommands: commandsForEffect("togglePlanMode"),
|
||||
localStatusCommands: commandsForEffect("showStatus"),
|
||||
localSpeedCommands: commandsForEffect("toggleSpeed")
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function resolveSlashCommandsForProvider({
|
||||
provider: _provider,
|
||||
policy,
|
||||
commands,
|
||||
hasCompactableContext = true,
|
||||
compactSupported,
|
||||
planSupported = false,
|
||||
browserSupported = false,
|
||||
computerSupported = false,
|
||||
tuttiSupported = false
|
||||
}: {
|
||||
provider: AgentSlashCommandProvider;
|
||||
policy?: AgentSlashCommandPolicy | null;
|
||||
commands: readonly AgentSessionCommand[];
|
||||
hasCompactableContext?: boolean;
|
||||
/**
|
||||
* Negotiated `compact` capability. `false` drops the command entirely
|
||||
* (including provider fallbacks); `undefined`/`null` means unknown and
|
||||
* keeps the legacy `hasCompactableContext` behavior.
|
||||
*/
|
||||
compactSupported?: boolean | null;
|
||||
planSupported?: boolean;
|
||||
browserSupported?: boolean;
|
||||
computerSupported?: boolean;
|
||||
tuttiSupported?: boolean;
|
||||
}): AgentSlashCommand[] {
|
||||
// Provider-advertised commands are runtime capabilities. Open extension
|
||||
// providers do not have a built-in Tutti policy descriptor, but their ACP
|
||||
// command catalog is still authoritative and must remain visible.
|
||||
const descriptorCommands = commands;
|
||||
const mergedEntries = mergeSlashCommands(
|
||||
filterUnavailableSlashCommands(descriptorCommands, {
|
||||
compactSupported,
|
||||
hasCompactableContext
|
||||
}),
|
||||
filterUnavailableSlashCommands(fallbackCommandsForPolicy(policy), {
|
||||
compactSupported,
|
||||
hasCompactableContext
|
||||
})
|
||||
);
|
||||
const localPlanAvailable =
|
||||
planSupported &&
|
||||
(providerSlashPolicy(policy)?.localPlanCommands.has("plan") ?? false);
|
||||
// `/plan` and `/tutti` are local modifiers, not agent prompts. Drop provider
|
||||
// entries that would shadow their reserved exact names, then re-surface the
|
||||
// local entries when the corresponding host support exists.
|
||||
const commandEntries = mergedEntries.filter((entry) => {
|
||||
const commandName = normalizedCommandName(entry);
|
||||
return (
|
||||
!isLocalTogglePlanCommand(commandName, policy) &&
|
||||
(!localPlanAvailable || !slashCommandMatchesInvocation(entry, "plan")) &&
|
||||
(!tuttiSupported || !slashCommandMatchesInvocation(entry, "tutti")) &&
|
||||
isSlashPaletteCommandVisible(commandName, policy)
|
||||
);
|
||||
});
|
||||
const planEntries = localPlanAvailable ? [PLAN_MODE_COMMAND] : [];
|
||||
const capabilityEntries: AgentSlashCommandCapability[] = [];
|
||||
if (browserSupported) {
|
||||
capabilityEntries.push(BROWSER_USE_CAPABILITY_COMMAND);
|
||||
}
|
||||
if (computerSupported) {
|
||||
capabilityEntries.push(COMPUTER_USE_CAPABILITY_COMMAND);
|
||||
}
|
||||
if (tuttiSupported) {
|
||||
capabilityEntries.push(TUTTI_CAPABILITY_COMMAND);
|
||||
}
|
||||
return [...commandEntries, ...planEntries, ...capabilityEntries];
|
||||
}
|
||||
|
||||
export function resolveSlashCommandSelectionEffect({
|
||||
provider: _provider,
|
||||
policy,
|
||||
command,
|
||||
currentDraft
|
||||
}: ResolveSlashCommandSelectionEffectInput): SlashCommandSelectionEffect | null {
|
||||
if (isBrowserUseCapability(command)) {
|
||||
return {
|
||||
kind: "enableBrowserUse",
|
||||
draft: draftForSlashCommand(command, currentDraft)
|
||||
};
|
||||
}
|
||||
if (isComputerUseCapability(command)) {
|
||||
return {
|
||||
kind: "enableComputerUse",
|
||||
draft: draftForSlashCommand(command, currentDraft)
|
||||
};
|
||||
}
|
||||
if (isTuttiCapability(command)) {
|
||||
return { kind: "activateTuttiMode" };
|
||||
}
|
||||
if (!policy) {
|
||||
return {
|
||||
kind: "fillDraft",
|
||||
draft: draftForSlashCommand(command, currentDraft)
|
||||
};
|
||||
}
|
||||
const commandName = normalizedCommandName(command);
|
||||
if (isLocalTogglePlanCommand(commandName, policy)) {
|
||||
return { kind: "enablePlanMode" };
|
||||
}
|
||||
if (isLocalGoalCommand(commandName, policy)) {
|
||||
return { kind: "activateGoalMode" };
|
||||
}
|
||||
if (isLocalToggleSpeedCommand(commandName, policy)) {
|
||||
return { kind: "toggleSpeed" };
|
||||
}
|
||||
if (isLocalStatusCommand(commandName, policy)) {
|
||||
return { kind: "showStatus" };
|
||||
}
|
||||
// A descriptor may route a bare palette command to a local picker.
|
||||
if (isReviewPickerCommand(commandName, policy)) {
|
||||
return { kind: "showReviewPicker" };
|
||||
}
|
||||
if (isImmediateCommand(commandName, policy)) {
|
||||
return {
|
||||
kind: "submitPrompt",
|
||||
prompt: promptForSlashCommand(command)
|
||||
};
|
||||
}
|
||||
return {
|
||||
kind: "fillDraft",
|
||||
draft: draftForSlashCommand(command, currentDraft)
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveSlashCommandSubmitEffect({
|
||||
browserSupported = false,
|
||||
computerSupported = false,
|
||||
tuttiSupported = false,
|
||||
provider: _provider,
|
||||
policy,
|
||||
commands,
|
||||
draft
|
||||
}: ResolveSlashCommandSubmitEffectInput): SlashCommandSelectionEffect | null {
|
||||
for (const [capability, supported] of [
|
||||
["browserUse", browserSupported],
|
||||
["computerUse", computerSupported]
|
||||
] as const) {
|
||||
const capabilityEffect = resolveCapabilitySubmitEffect({
|
||||
capability,
|
||||
commands,
|
||||
draft,
|
||||
supported
|
||||
});
|
||||
if (capabilityEffect) {
|
||||
return capabilityEffect;
|
||||
}
|
||||
}
|
||||
const invocation = parseSlashCommandInvocation(draft);
|
||||
if (!invocation) {
|
||||
return null;
|
||||
}
|
||||
const command = commands.find((candidate) =>
|
||||
slashCommandMatchesInvocation(candidate, invocation.commandName)
|
||||
);
|
||||
if (!command) {
|
||||
return null;
|
||||
}
|
||||
if (isAgentSlashCommandCapability(command)) {
|
||||
return tuttiSupported &&
|
||||
isTuttiCapability(command) &&
|
||||
invocation.args.trim() === ""
|
||||
? { kind: "activateTuttiMode" }
|
||||
: null;
|
||||
}
|
||||
const commandName = normalizedCommandName(command);
|
||||
if (isLocalTogglePlanCommand(commandName, policy)) {
|
||||
return invocation.args.trim() === "" ? { kind: "enablePlanMode" } : null;
|
||||
}
|
||||
if (isLocalGoalCommand(commandName, policy)) {
|
||||
return invocation.args.trim() === "" ? { kind: "activateGoalMode" } : null;
|
||||
}
|
||||
if (isLocalToggleSpeedCommand(commandName, policy)) {
|
||||
return { kind: "toggleSpeed" };
|
||||
}
|
||||
if (isLocalStatusCommand(commandName, policy)) {
|
||||
return { kind: "showStatus" };
|
||||
}
|
||||
// Bare `/review` opens the target picker; `/review <text>` keeps the legacy
|
||||
// behavior of submitting the text straight through as a custom review.
|
||||
if (isReviewPickerCommand(commandName, policy)) {
|
||||
return invocation.args.trim() === "" ? { kind: "showReviewPicker" } : null;
|
||||
}
|
||||
if (isImmediateCommand(commandName, policy)) {
|
||||
return {
|
||||
kind: "submitPrompt",
|
||||
prompt: invocation.normalizedPrompt
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolveCapabilitySubmitEffect({
|
||||
capability,
|
||||
commands,
|
||||
draft,
|
||||
supported
|
||||
}: {
|
||||
capability: AgentCapabilityUse;
|
||||
commands: readonly AgentSlashCommand[];
|
||||
draft: string;
|
||||
supported: boolean;
|
||||
}): SlashCommandSelectionEffect | null {
|
||||
if (!supported) {
|
||||
return null;
|
||||
}
|
||||
const invocation = parseAgentCapabilityUseInvocation(draft, capability);
|
||||
if (!invocation) {
|
||||
return null;
|
||||
}
|
||||
const command = commands.find((candidate) =>
|
||||
slashCommandMatchesInvocation(candidate, invocation.commandName)
|
||||
);
|
||||
if (!command || !isCapabilityCommand(command, capability)) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
kind: "submitPrompt",
|
||||
prompt: buildAgentCapabilityUseSubmitPrompt(capability, invocation.args),
|
||||
displayPrompt: agentCapabilityUseDisplayPrompt(capability, invocation.args),
|
||||
requiredSettingsPatch: { [capability]: true }
|
||||
};
|
||||
}
|
||||
|
||||
function isLocalTogglePlanCommand(
|
||||
commandName: string,
|
||||
policy?: AgentSlashCommandPolicy | null
|
||||
): boolean {
|
||||
return (
|
||||
providerSlashPolicy(policy)?.localPlanCommands.has(
|
||||
commandName.trim().toLowerCase()
|
||||
) ?? false
|
||||
);
|
||||
}
|
||||
|
||||
function isLocalGoalCommand(
|
||||
commandName: string,
|
||||
policy?: AgentSlashCommandPolicy | null
|
||||
): boolean {
|
||||
return (
|
||||
providerSlashPolicy(policy)?.localGoalCommands.has(
|
||||
commandName.trim().toLowerCase()
|
||||
) ?? false
|
||||
);
|
||||
}
|
||||
|
||||
function isReviewPickerCommand(
|
||||
commandName: string,
|
||||
policy?: AgentSlashCommandPolicy | null
|
||||
): boolean {
|
||||
return (
|
||||
providerSlashPolicy(policy)?.reviewPickerCommands.has(commandName) ?? false
|
||||
);
|
||||
}
|
||||
|
||||
function fallbackCommandsForPolicy(
|
||||
policy?: AgentSlashCommandPolicy | null
|
||||
): readonly AgentSessionCommand[] {
|
||||
return providerSlashPolicy(policy)?.fallbackCommands ?? [];
|
||||
}
|
||||
|
||||
function isSlashPaletteCommandVisible(
|
||||
commandName: string,
|
||||
policy?: AgentSlashCommandPolicy | null
|
||||
): boolean {
|
||||
// AgentGUI injects /side only when the host provides the provider-neutral
|
||||
// Side runtime. It is a host command and therefore is not expected to be in
|
||||
// a provider's authoritative command catalog.
|
||||
if (commandName === "side") {
|
||||
return true;
|
||||
}
|
||||
if (policy?.commandCatalogAuthoritative === true) {
|
||||
const fallbackCommands = Array.isArray(policy.fallbackCommands)
|
||||
? policy.fallbackCommands
|
||||
: [];
|
||||
const commandEffects = Array.isArray(policy.commandEffects)
|
||||
? policy.commandEffects
|
||||
: [];
|
||||
return (
|
||||
fallbackCommands.some(
|
||||
(command) => command.trim().toLowerCase() === commandName
|
||||
) ||
|
||||
commandEffects.some(
|
||||
(descriptor) => descriptor.command.trim().toLowerCase() === commandName
|
||||
)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function isLocalStatusCommand(
|
||||
commandName: string,
|
||||
policy?: AgentSlashCommandPolicy | null
|
||||
): boolean {
|
||||
return (
|
||||
providerSlashPolicy(policy)?.localStatusCommands.has(commandName) ?? false
|
||||
);
|
||||
}
|
||||
|
||||
function isLocalToggleSpeedCommand(
|
||||
commandName: string,
|
||||
policy?: AgentSlashCommandPolicy | null
|
||||
): boolean {
|
||||
return (
|
||||
providerSlashPolicy(policy)?.localSpeedCommands.has(commandName) ?? false
|
||||
);
|
||||
}
|
||||
|
||||
function isImmediateCommand(
|
||||
commandName: string,
|
||||
policy?: AgentSlashCommandPolicy | null
|
||||
): boolean {
|
||||
return (
|
||||
providerSlashPolicy(policy)?.immediateCommands.has(commandName) ?? false
|
||||
);
|
||||
}
|
||||
|
||||
function normalizedCommandSet(values: readonly string[]): ReadonlySet<string> {
|
||||
return new Set(
|
||||
values.map((value) => value.trim().toLowerCase()).filter(Boolean)
|
||||
);
|
||||
}
|
||||
|
||||
export function slashCommandPolicyFromComposerOptions(
|
||||
options: AgentActivityComposerOptions | null
|
||||
): AgentSlashCommandPolicy | null {
|
||||
return options?.slashCommandPolicy ?? null;
|
||||
}
|
||||
|
||||
function normalizedCommandName(command: { name: string }): string {
|
||||
return command.name.trim().toLowerCase();
|
||||
}
|
||||
|
||||
function isBrowserUseCapability(
|
||||
command: AgentSlashCommand
|
||||
): command is AgentSlashCommandCapability {
|
||||
return (
|
||||
"kind" in command &&
|
||||
command.kind === "capability" &&
|
||||
command.capability === "browserUse"
|
||||
);
|
||||
}
|
||||
|
||||
function isComputerUseCapability(
|
||||
command: AgentSlashCommand
|
||||
): command is AgentSlashCommandCapability {
|
||||
return (
|
||||
"kind" in command &&
|
||||
command.kind === "capability" &&
|
||||
command.capability === "computerUse"
|
||||
);
|
||||
}
|
||||
|
||||
function isTuttiCapability(
|
||||
command: AgentSlashCommand
|
||||
): command is AgentSlashCommandCapability & { capability: "tutti" } {
|
||||
return (
|
||||
"kind" in command &&
|
||||
command.kind === "capability" &&
|
||||
command.capability === "tutti"
|
||||
);
|
||||
}
|
||||
|
||||
function isCapabilityCommand(
|
||||
command: AgentSlashCommand,
|
||||
capability: AgentSlashCommandCapability["capability"]
|
||||
): command is AgentSlashCommandCapability {
|
||||
return (
|
||||
"kind" in command &&
|
||||
command.kind === "capability" &&
|
||||
command.capability === capability
|
||||
);
|
||||
}
|
||||
|
||||
function isAgentSlashCommandCapability(
|
||||
command: AgentSlashCommand
|
||||
): command is AgentSlashCommandCapability {
|
||||
return "kind" in command && command.kind === "capability";
|
||||
}
|
||||
|
||||
function slashCommandMatchesInvocation(
|
||||
command: AgentSlashCommand,
|
||||
commandName: string
|
||||
): boolean {
|
||||
const normalizedInvocation = commandName.trim().toLowerCase();
|
||||
if (normalizedCommandName(command) === normalizedInvocation) {
|
||||
return true;
|
||||
}
|
||||
const aliases = "aliases" in command ? (command.aliases ?? []) : [];
|
||||
return aliases.some(
|
||||
(alias) => alias.trim().toLowerCase() === normalizedInvocation
|
||||
);
|
||||
}
|
||||
|
||||
function filterUnavailableSlashCommands(
|
||||
commands: readonly AgentSessionCommand[],
|
||||
input: {
|
||||
compactSupported?: boolean | null;
|
||||
hasCompactableContext: boolean;
|
||||
}
|
||||
): AgentSessionCommand[] {
|
||||
return commands.filter((command) => {
|
||||
const commandName = normalizedCommandName(command);
|
||||
if (commandName === "compact") {
|
||||
if (input.compactSupported === false) {
|
||||
return false;
|
||||
}
|
||||
return input.hasCompactableContext;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user