mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-06 19:58:43 +02:00
feat: add structured prompt invocation backend
- parse prompt tools metadata and carry structured promptInvocation payloads - store prompt invocation metadata on trigger messages for replay-safe reruns - route prompt agents through per-turn plan or Copilot agent overrides - restrict prompt-scoped tools in sidecar session configuration - auto-rescan project customization files with debounced watchers - document the new customization watcher and prompt invocation flow Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -37,11 +37,22 @@ export interface ProjectPromptFile {
|
||||
name: string;
|
||||
description?: string;
|
||||
agent?: string;
|
||||
tools?: string[];
|
||||
template: string;
|
||||
variables: ProjectPromptVariable[];
|
||||
sourcePath: string;
|
||||
}
|
||||
|
||||
export interface ProjectPromptInvocation {
|
||||
id: string;
|
||||
name: string;
|
||||
sourcePath: string;
|
||||
resolvedPrompt: string;
|
||||
description?: string;
|
||||
agent?: string;
|
||||
tools?: string[];
|
||||
}
|
||||
|
||||
export interface ProjectCustomizationState {
|
||||
instructions: ProjectInstructionFile[];
|
||||
agentProfiles: ProjectAgentProfile[];
|
||||
@@ -262,9 +273,54 @@ function normalizeProjectPromptFile(promptFile: ProjectPromptFile): ProjectPromp
|
||||
normalizedPromptFile.agent = agent;
|
||||
}
|
||||
|
||||
const tools = normalizeOptionalStringArray(promptFile.tools);
|
||||
if (tools) {
|
||||
normalizedPromptFile.tools = tools;
|
||||
}
|
||||
|
||||
return normalizedPromptFile;
|
||||
}
|
||||
|
||||
export function normalizeProjectPromptInvocation(
|
||||
promptInvocation?: ProjectPromptInvocation,
|
||||
): ProjectPromptInvocation | undefined {
|
||||
if (!promptInvocation) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const normalizedPromptInvocation: ProjectPromptInvocation = {
|
||||
id: promptInvocation.id.trim(),
|
||||
name: promptInvocation.name.trim(),
|
||||
sourcePath: normalizePathLikeString(promptInvocation.sourcePath),
|
||||
resolvedPrompt: promptInvocation.resolvedPrompt.trim(),
|
||||
};
|
||||
|
||||
if (
|
||||
normalizedPromptInvocation.id.length === 0
|
||||
|| normalizedPromptInvocation.name.length === 0
|
||||
|| normalizedPromptInvocation.resolvedPrompt.length === 0
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const description = normalizeOptionalString(promptInvocation.description);
|
||||
if (description) {
|
||||
normalizedPromptInvocation.description = description;
|
||||
}
|
||||
|
||||
const agent = normalizeOptionalString(promptInvocation.agent);
|
||||
if (agent) {
|
||||
normalizedPromptInvocation.agent = agent;
|
||||
}
|
||||
|
||||
const tools = normalizeOptionalStringArray(promptInvocation.tools);
|
||||
if (tools) {
|
||||
normalizedPromptInvocation.tools = tools;
|
||||
}
|
||||
|
||||
return normalizedPromptInvocation;
|
||||
}
|
||||
|
||||
function compareProjectFiles(
|
||||
left: Pick<ProjectInstructionFile | ProjectAgentProfile | ProjectPromptFile, 'sourcePath' | 'id'>,
|
||||
right: Pick<ProjectInstructionFile | ProjectAgentProfile | ProjectPromptFile, 'sourcePath' | 'id'>,
|
||||
|
||||
@@ -16,6 +16,10 @@ import type { PendingPlanReviewRecord } from '@shared/domain/planReview';
|
||||
import type { PendingMcpAuthRecord } from '@shared/domain/mcpAuth';
|
||||
import type { ChatMessageAttachment } from '@shared/domain/attachment';
|
||||
import type { InteractionMode } from '@shared/contracts/sidecar';
|
||||
import {
|
||||
normalizeProjectPromptInvocation,
|
||||
type ProjectPromptInvocation,
|
||||
} from '@shared/domain/projectCustomization';
|
||||
|
||||
export type ChatRole = 'system' | 'user' | 'assistant';
|
||||
export type ChatMessageKind = 'response' | 'thinking';
|
||||
@@ -38,6 +42,7 @@ export interface ChatMessageRecord {
|
||||
isPinned?: boolean;
|
||||
pending?: boolean;
|
||||
attachments?: ChatMessageAttachment[];
|
||||
promptInvocation?: ProjectPromptInvocation;
|
||||
}
|
||||
|
||||
export interface SessionBranchOrigin {
|
||||
@@ -166,6 +171,20 @@ export function resolveSessionModelConfig(
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizeChatMessageRecord(message: ChatMessageRecord): ChatMessageRecord {
|
||||
const normalizedMessage: ChatMessageRecord = {
|
||||
...message,
|
||||
};
|
||||
const promptInvocation = normalizeProjectPromptInvocation(message.promptInvocation);
|
||||
if (promptInvocation) {
|
||||
normalizedMessage.promptInvocation = promptInvocation;
|
||||
} else {
|
||||
delete normalizedMessage.promptInvocation;
|
||||
}
|
||||
|
||||
return normalizedMessage;
|
||||
}
|
||||
|
||||
export function applySessionModelConfig(
|
||||
pattern: PatternDefinition,
|
||||
session: SessionRecord,
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { PatternDefinition } from '@shared/domain/pattern';
|
||||
import { isScratchpadProject, type ProjectRecord } from '@shared/domain/project';
|
||||
import type { ChatMessageAttachment } from '@shared/domain/attachment';
|
||||
import {
|
||||
normalizeProjectPromptInvocation,
|
||||
type ProjectPromptInvocation,
|
||||
} from '@shared/domain/projectCustomization';
|
||||
import {
|
||||
resolveSessionTitle,
|
||||
type ChatMessageRecord,
|
||||
@@ -175,11 +179,26 @@ function cloneAttachments(attachments?: ChatMessageAttachment[]): ChatMessageAtt
|
||||
return cloned && cloned.length > 0 ? cloned : undefined;
|
||||
}
|
||||
|
||||
function clonePromptInvocation(
|
||||
promptInvocation?: ProjectPromptInvocation,
|
||||
): ProjectPromptInvocation | undefined {
|
||||
const cloned = normalizeProjectPromptInvocation(promptInvocation);
|
||||
if (!cloned) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
...cloned,
|
||||
tools: cloned.tools ? [...cloned.tools] : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
function cloneChatMessageRecord(message: ChatMessageRecord): ChatMessageRecord {
|
||||
return {
|
||||
...message,
|
||||
pending: false,
|
||||
attachments: cloneAttachments(message.attachments),
|
||||
promptInvocation: clonePromptInvocation(message.promptInvocation),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -386,6 +405,7 @@ export function editAndResendSessionRecord(
|
||||
|
||||
editedMessage.content = content;
|
||||
editedMessage.attachments = cloneAttachments(attachments);
|
||||
editedMessage.promptInvocation = undefined;
|
||||
|
||||
return {
|
||||
...createDerivedSessionRecord(session, sessionId, editedAt),
|
||||
|
||||
Reference in New Issue
Block a user