@elyracode/coding-agent 0.5.13 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +6 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +35 -7
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +1 -1
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/extensions/types.d.ts +1 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/keybindings.d.ts +1 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +25 -27
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/smart-router.d.ts +2 -2
- package/dist/core/smart-router.d.ts.map +1 -1
- package/dist/core/smart-router.js +64 -10
- package/dist/core/smart-router.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +2 -9
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +87 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smart-router.js","sourceRoot":"","sources":["../../src/core/smart-router.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Smart model routing for automatic tier-based model selection.\n *\n * Analyzes conversation signals after each turn and selects the optimal model\n * tier (fast/balanced/powerful) for the next turn based on task complexity.\n */\n\nimport type { AgentMessage, ThinkingLevel } from \"@elyracode/agent-core\";\nimport type { Api, AssistantMessage, Model, ToolCall, ToolResultMessage, UserMessage } from \"@elyracode/ai\";\nimport { modelsAreEqual } from \"@elyracode/ai\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SmartRouterConfig {\n\tenabled: boolean;\n\t/** Available models the router can pick from. Must have at least one. */\n\tavailableModels: Model<Api>[];\n\t/** The user's preferred/current model -- used as the Tier 2 default and fallback. */\n\tpreferredModel: Model<Api>;\n}\n\nexport interface TurnAnalysis {\n\t/** The messages in the conversation so far. */\n\tmessages: readonly AgentMessage[];\n\t/** Current thinking level. */\n\tthinkingLevel: ThinkingLevel;\n}\n\nexport type ComplexityTier = \"fast\" | \"balanced\" | \"powerful\";\n\nexport interface SmartRouterResult {\n\tmodel: Model<Api>;\n\ttier: ComplexityTier;\n\treason: string;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Output cost thresholds ($/million tokens) for tier classification. */\nconst TIER_1_MAX_COST = 3;\nconst TIER_3_MIN_COST = 20;\n\n/** Tool names considered read-only (no side effects). */\nconst READ_ONLY_TOOLS: ReadonlySet<string> = new Set([\"read\", \"grep\", \"find\", \"ls\"]);\n\n/** Keywords in user messages that signal complex work. */\nconst COMPLEX_KEYWORDS: readonly string[] = [\n\t\"refactor\",\n\t\"architect\",\n\t\"redesign\",\n\t\"migrate\",\n\t\"rewrite\",\n\t\"debug\",\n\t\"fix the bug\",\n\t\"security audit\",\n];\n\n/** Short user message threshold (characters). */\nconst SHORT_MESSAGE_THRESHOLD = 100;\n\n/** Message count threshold for complex multi-step tasks. */\nconst LONG_CONVERSATION_THRESHOLD = 20;\n\n/** File edit count threshold per turn for complexity escalation. */\nconst MANY_EDITS_THRESHOLD = 3;\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction isUserMessage(msg: AgentMessage): msg is UserMessage {\n\treturn \"role\" in msg && (msg as UserMessage).role === \"user\";\n}\n\nfunction isAssistantMessage(msg: AgentMessage): msg is AssistantMessage {\n\treturn \"role\" in msg && (msg as AssistantMessage).role === \"assistant\";\n}\n\nfunction isToolResultMessage(msg: AgentMessage): msg is ToolResultMessage {\n\treturn \"role\" in msg && (msg as ToolResultMessage).role === \"toolResult\";\n}\n\n/** Extract the plain-text content of a user message. */\nfunction getUserMessageText(msg: UserMessage): string {\n\tif (typeof msg.content === \"string\") return msg.content;\n\treturn msg.content\n\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t.map((c) => c.text)\n\t\t.join(\" \");\n}\n\n/** Extract tool calls from an assistant message's content. */\nfunction getToolCalls(msg: AssistantMessage): ToolCall[] {\n\treturn msg.content.filter((c): c is ToolCall => c.type === \"toolCall\");\n}\n\n/** True when all tool calls in a message are read-only. */\nfunction allToolCallsReadOnly(toolCalls: ToolCall[]): boolean {\n\treturn toolCalls.length > 0 && toolCalls.every((tc) => READ_ONLY_TOOLS.has(tc.name));\n}\n\n/** Count write/edit tool calls in an assistant message. */\nfunction countFileEditCalls(toolCalls: ToolCall[]): number {\n\treturn toolCalls.filter((tc) => tc.name === \"write\" || tc.name === \"edit\").length;\n}\n\n/**\n * Collect tool result messages that follow an assistant message.\n * Walks forward from the assistant message index, collecting consecutive\n * tool results (there may be other message types interleaved in custom\n * AgentMessage streams, so we stop at the next user or assistant message).\n */\nfunction getToolResultsAfter(messages: readonly AgentMessage[], assistantIndex: number): ToolResultMessage[] {\n\tconst results: ToolResultMessage[] = [];\n\tfor (let i = assistantIndex + 1; i < messages.length; i++) {\n\t\tconst msg = messages[i];\n\t\tif (isUserMessage(msg) || isAssistantMessage(msg)) break;\n\t\tif (isToolResultMessage(msg)) results.push(msg);\n\t}\n\treturn results;\n}\n\n/** True when the text contains any of the complex keywords (case-insensitive). */\nfunction containsComplexKeyword(text: string): boolean {\n\tconst lower = text.toLowerCase();\n\treturn COMPLEX_KEYWORDS.some((kw) => lower.includes(kw));\n}\n\n// ============================================================================\n// Tier classification\n// ============================================================================\n\n/** Classify a model into its cost tier. */\nfunction modelTier(model: Model<Api>): ComplexityTier {\n\tconst cost = model.cost.output;\n\tif (cost < TIER_1_MAX_COST) return \"fast\";\n\tif (cost < TIER_3_MIN_COST) return \"balanced\";\n\treturn \"powerful\";\n}\n\n/** Classify the complexity tier for the next turn. */\nexport function classifyComplexity(analysis: TurnAnalysis): { tier: ComplexityTier; reason: string } {\n\tconst { messages, thinkingLevel } = analysis;\n\n\t// High thinking level -> complex\n\tif (thinkingLevel === \"high\" || thinkingLevel === \"xhigh\") {\n\t\treturn { tier: \"powerful\", reason: `thinking level is set to ${thinkingLevel}` };\n\t}\n\n\t// Long conversation -> complex\n\tif (messages.length > LONG_CONVERSATION_THRESHOLD) {\n\t\treturn { tier: \"powerful\", reason: `long conversation (${messages.length} messages)` };\n\t}\n\n\t// Find the last assistant message and its tool results\n\tlet lastAssistantIndex = -1;\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tif (isAssistantMessage(messages[i])) {\n\t\t\tlastAssistantIndex = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Find the last user message\n\tlet lastUserMessage: UserMessage | undefined;\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tif (isUserMessage(messages[i])) {\n\t\t\tlastUserMessage = messages[i] as UserMessage;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Check for complex signals from the last assistant turn\n\tif (lastAssistantIndex >= 0) {\n\t\tconst lastAssistant = messages[lastAssistantIndex] as AssistantMessage;\n\t\tconst toolCalls = getToolCalls(lastAssistant);\n\t\tconst toolResults = getToolResultsAfter(messages, lastAssistantIndex);\n\n\t\t// Errors in last turn -> complex\n\t\tconst hasErrors = toolResults.some((tr) => tr.isError);\n\t\tif (hasErrors) {\n\t\t\treturn { tier: \"powerful\", reason: \"tool errors in last turn\" };\n\t\t}\n\n\t\t// Many file edits in last turn -> complex\n\t\tif (countFileEditCalls(toolCalls) > MANY_EDITS_THRESHOLD) {\n\t\t\treturn { tier: \"powerful\", reason: `many file edits in last turn (${countFileEditCalls(toolCalls)})` };\n\t\t}\n\n\t\t// All read-only tools and no errors -> check for simple\n\t\tif (allToolCallsReadOnly(toolCalls) && !hasErrors) {\n\t\t\t// If the last user message is also short and simple, use fast tier\n\t\t\tif (lastUserMessage) {\n\t\t\t\tconst text = getUserMessageText(lastUserMessage);\n\t\t\t\tif (text.length < SHORT_MESSAGE_THRESHOLD && !containsComplexKeyword(text)) {\n\t\t\t\t\treturn { tier: \"fast\", reason: \"read-only tools with short user message\" };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check user message for complex keywords\n\tif (lastUserMessage) {\n\t\tconst text = getUserMessageText(lastUserMessage);\n\t\tif (containsComplexKeyword(text)) {\n\t\t\treturn { tier: \"powerful\", reason: \"complex keywords in user message\" };\n\t\t}\n\n\t\t// Short question with no prior assistant context -> fast\n\t\tif (lastAssistantIndex < 0 && text.length < SHORT_MESSAGE_THRESHOLD) {\n\t\t\treturn { tier: \"fast\", reason: \"short initial message\" };\n\t\t}\n\t}\n\n\treturn { tier: \"balanced\", reason: \"default\" };\n}\n\n// ============================================================================\n// Model selection\n// ============================================================================\n\n/** Select the best model for a given complexity tier from available models. */\nexport function selectModelForTier(tier: ComplexityTier, config: SmartRouterConfig): Model<Api> {\n\tconst { availableModels, preferredModel } = config;\n\n\t// Partition models into tiers\n\tconst tierModels = availableModels.filter((m) => modelTier(m) === tier);\n\n\tif (tierModels.length === 0) {\n\t\t// Requested tier has no models, fall back to preferred\n\t\treturn preferredModel;\n\t}\n\n\t// Pick the model with the largest context window (best value within tier)\n\tlet best = tierModels[0];\n\tfor (let i = 1; i < tierModels.length; i++) {\n\t\tif (tierModels[i].contextWindow > best.contextWindow) {\n\t\t\tbest = tierModels[i];\n\t\t}\n\t}\n\treturn best;\n}\n\n// ============================================================================\n// Main entry\n// ============================================================================\n\n/**\n * Analyze the turn and return a model recommendation.\n *\n * Returns undefined when:\n * - Smart routing is disabled\n * - The selected model is the same as the preferred model (no change needed)\n */\nexport function routeNextTurn(analysis: TurnAnalysis, config: SmartRouterConfig): SmartRouterResult | undefined {\n\tif (!config.enabled) return undefined;\n\n\tconst { tier, reason } = classifyComplexity(analysis);\n\tconst model = selectModelForTier(tier, config);\n\n\t// No change needed if the router picks the same model the user already has\n\tif (modelsAreEqual(model, config.preferredModel)) return undefined;\n\n\treturn { model, tier, reason };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"smart-router.js","sourceRoot":"","sources":["../../src/core/smart-router.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Smart model routing for automatic tier-based model selection.\n *\n * Analyzes conversation signals after each turn and selects the optimal model\n * tier (fast/balanced/powerful) for the next turn based on task complexity.\n */\n\nimport type { AgentMessage, ThinkingLevel } from \"@elyracode/agent-core\";\nimport type { Api, AssistantMessage, Model, ToolCall, ToolResultMessage, UserMessage } from \"@elyracode/ai\";\nimport { modelsAreEqual } from \"@elyracode/ai\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SmartRouterConfig {\n\tenabled: boolean;\n\t/** Available models the router can pick from. Must have at least one. */\n\tavailableModels: Model<Api>[];\n\t/** The user's preferred/current model -- used as the Tier 2 default and fallback. */\n\tpreferredModel: Model<Api>;\n}\n\nexport interface TurnAnalysis {\n\t/** The messages in the conversation so far. */\n\tmessages: readonly AgentMessage[];\n\t/** Current thinking level. */\n\tthinkingLevel: ThinkingLevel;\n}\n\nexport type ComplexityTier = \"fast\" | \"balanced\" | \"powerful\";\n\nexport interface SmartRouterResult {\n\tmodel: Model<Api>;\n\ttier: ComplexityTier;\n\treason: string;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Output cost thresholds ($/million tokens) for tier classification. */\nconst TIER_1_MAX_COST = 3;\nconst TIER_3_MIN_COST = 20;\n\n/** Tool names considered read-only (no side effects). */\nconst READ_ONLY_TOOLS: ReadonlySet<string> = new Set([\"read\", \"grep\", \"find\", \"ls\"]);\n\n/** Keywords in user messages that signal complex work. */\nconst COMPLEX_KEYWORDS: readonly string[] = [\n\t\"refactor\",\n\t\"architect\",\n\t\"redesign\",\n\t\"migrate\",\n\t\"rewrite\",\n\t\"debug\",\n\t\"fix the bug\",\n\t\"security audit\",\n\t\"optimize\",\n\t\"performance\",\n\t\"investigate\",\n\t\"diagnose\",\n\t\"troubleshoot\",\n\t\"root cause\",\n\t\"race condition\",\n\t\"deadlock\",\n\t\"memory leak\",\n\t\"regression\",\n\t\"breaking change\",\n\t\"backwards compatible\",\n\t\"design pattern\",\n\t\"abstraction\",\n\t\"inheritance\",\n\t\"polymorphism\",\n\t\"dependency injection\",\n\t\"restructure\",\n\t\"consolidate\",\n\t\"decompose\",\n\t\"decouple\",\n\t\"integrate\",\n\t\"implement from scratch\",\n\t\"build a system\",\n\t\"complex\",\n\t\"tricky\",\n\t\"subtle\",\n];\n\n/** Short user message threshold (characters). */\nconst SHORT_MESSAGE_THRESHOLD = 100;\n\n/** Message count threshold for complex multi-step tasks. */\nconst LONG_CONVERSATION_THRESHOLD = 20;\n\n/** File edit count threshold per turn for complexity escalation. */\nconst MANY_EDITS_THRESHOLD = 3;\n\n/** Character count threshold for large tool output. */\nconst LARGE_TOOL_OUTPUT_THRESHOLD = 5000;\n\n/** Conversation length below which read-only de-escalation to fast is allowed. */\nconst READ_ONLY_DEESCALATION_MAX_MESSAGES = 10;\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction isUserMessage(msg: AgentMessage): msg is UserMessage {\n\treturn \"role\" in msg && (msg as UserMessage).role === \"user\";\n}\n\nfunction isAssistantMessage(msg: AgentMessage): msg is AssistantMessage {\n\treturn \"role\" in msg && (msg as AssistantMessage).role === \"assistant\";\n}\n\nfunction isToolResultMessage(msg: AgentMessage): msg is ToolResultMessage {\n\treturn \"role\" in msg && (msg as ToolResultMessage).role === \"toolResult\";\n}\n\n/** Extract the plain-text content of a user message. */\nfunction getUserMessageText(msg: UserMessage): string {\n\tif (typeof msg.content === \"string\") return msg.content;\n\treturn msg.content\n\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t.map((c) => c.text)\n\t\t.join(\" \");\n}\n\n/** Extract tool calls from an assistant message's content. */\nfunction getToolCalls(msg: AssistantMessage): ToolCall[] {\n\treturn msg.content.filter((c): c is ToolCall => c.type === \"toolCall\");\n}\n\n/** True when all tool calls in a message are read-only. */\nfunction allToolCallsReadOnly(toolCalls: ToolCall[]): boolean {\n\treturn toolCalls.length > 0 && toolCalls.every((tc) => READ_ONLY_TOOLS.has(tc.name));\n}\n\n/** Count write/edit tool calls in an assistant message. */\nfunction countFileEditCalls(toolCalls: ToolCall[]): number {\n\treturn toolCalls.filter((tc) => tc.name === \"write\" || tc.name === \"edit\").length;\n}\n\n/**\n * Collect tool result messages that follow an assistant message.\n * Walks forward from the assistant message index, collecting consecutive\n * tool results (there may be other message types interleaved in custom\n * AgentMessage streams, so we stop at the next user or assistant message).\n */\nfunction getToolResultsAfter(messages: readonly AgentMessage[], assistantIndex: number): ToolResultMessage[] {\n\tconst results: ToolResultMessage[] = [];\n\tfor (let i = assistantIndex + 1; i < messages.length; i++) {\n\t\tconst msg = messages[i];\n\t\tif (isUserMessage(msg) || isAssistantMessage(msg)) break;\n\t\tif (isToolResultMessage(msg)) results.push(msg);\n\t}\n\treturn results;\n}\n\n/** True when the text contains any of the complex keywords (case-insensitive). */\nfunction containsComplexKeyword(text: string): boolean {\n\tconst lower = text.toLowerCase();\n\treturn COMPLEX_KEYWORDS.some((kw) => lower.includes(kw));\n}\n\n// ============================================================================\n// Tier classification\n// ============================================================================\n\n/** Classify a model into its cost tier. */\nfunction modelTier(model: Model<Api>): ComplexityTier {\n\tconst cost = model.cost.output;\n\tif (cost < TIER_1_MAX_COST) return \"fast\";\n\tif (cost < TIER_3_MIN_COST) return \"balanced\";\n\treturn \"powerful\";\n}\n\n/** Measure the total text length of a tool result message. */\nfunction toolResultTextLength(tr: ToolResultMessage): number {\n\treturn tr.content\n\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t.reduce((sum, c) => sum + c.text.length, 0);\n}\n\n/** Classify the complexity tier for the next turn. */\nexport function classifyComplexity(\n\tanalysis: TurnAnalysis,\n\tpreviousTier?: ComplexityTier,\n): { tier: ComplexityTier; reason: string } {\n\tconst { messages, thinkingLevel } = analysis;\n\n\t// High thinking level -> complex\n\tif (thinkingLevel === \"high\" || thinkingLevel === \"xhigh\") {\n\t\treturn { tier: \"powerful\", reason: `thinking level is set to ${thinkingLevel}` };\n\t}\n\n\t// Long conversation -> complex\n\tif (messages.length > LONG_CONVERSATION_THRESHOLD) {\n\t\treturn { tier: \"powerful\", reason: `long conversation (${messages.length} messages)` };\n\t}\n\n\t// Find the last assistant message and its tool results\n\tlet lastAssistantIndex = -1;\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tif (isAssistantMessage(messages[i])) {\n\t\t\tlastAssistantIndex = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Find the last user message\n\tlet lastUserMessage: UserMessage | undefined;\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tif (isUserMessage(messages[i])) {\n\t\t\tlastUserMessage = messages[i] as UserMessage;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Check for complex signals from the last assistant turn\n\tif (lastAssistantIndex >= 0) {\n\t\tconst lastAssistant = messages[lastAssistantIndex] as AssistantMessage;\n\t\tconst toolCalls = getToolCalls(lastAssistant);\n\t\tconst toolResults = getToolResultsAfter(messages, lastAssistantIndex);\n\n\t\t// Errors in last turn -> complex\n\t\tconst hasErrors = toolResults.some((tr) => tr.isError);\n\t\tif (hasErrors) {\n\t\t\treturn { tier: \"powerful\", reason: \"tool errors in last turn\" };\n\t\t}\n\n\t\t// Many file edits in last turn -> complex\n\t\tif (countFileEditCalls(toolCalls) > MANY_EDITS_THRESHOLD) {\n\t\t\treturn applyHysteresis(\n\t\t\t\t{ tier: \"powerful\", reason: `many file edits in last turn (${countFileEditCalls(toolCalls)})` },\n\t\t\t\tpreviousTier,\n\t\t\t);\n\t\t}\n\n\t\t// Large tool outputs suggest complex operations\n\t\tif (toolResults.some((r) => toolResultTextLength(r) > LARGE_TOOL_OUTPUT_THRESHOLD)) {\n\t\t\treturn applyHysteresis({ tier: \"powerful\", reason: \"large tool output detected\" }, previousTier);\n\t\t}\n\n\t\t// All read-only tools and no errors -> check for simple\n\t\tif (allToolCallsReadOnly(toolCalls) && !hasErrors) {\n\t\t\t// If the last user message is also short and simple, use fast tier.\n\t\t\t// Only de-escalate in short conversations; in longer ones a read-only\n\t\t\t// turn in the middle of complex work shouldn't drop to fast.\n\t\t\tif (lastUserMessage && messages.length < READ_ONLY_DEESCALATION_MAX_MESSAGES) {\n\t\t\t\tconst text = getUserMessageText(lastUserMessage);\n\t\t\t\tif (text.length < SHORT_MESSAGE_THRESHOLD && !containsComplexKeyword(text)) {\n\t\t\t\t\treturn applyHysteresis(\n\t\t\t\t\t\t{ tier: \"fast\", reason: \"read-only tools with short user message\" },\n\t\t\t\t\t\tpreviousTier,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check user message for complex keywords\n\tif (lastUserMessage) {\n\t\tconst text = getUserMessageText(lastUserMessage);\n\t\tif (containsComplexKeyword(text)) {\n\t\t\treturn applyHysteresis({ tier: \"powerful\", reason: \"complex keywords in user message\" }, previousTier);\n\t\t}\n\n\t\t// Short question with no prior assistant context -> fast\n\t\tif (lastAssistantIndex < 0 && text.length < SHORT_MESSAGE_THRESHOLD) {\n\t\t\treturn applyHysteresis({ tier: \"fast\", reason: \"short initial message\" }, previousTier);\n\t\t}\n\t}\n\n\treturn applyHysteresis({ tier: \"balanced\", reason: \"default\" }, previousTier);\n}\n\n/**\n * Hysteresis: prevent oscillation by not dropping from powerful directly to fast.\n * If the previous turn was powerful and the current classification is fast,\n * dampen to balanced instead.\n */\nfunction applyHysteresis(\n\tresult: { tier: ComplexityTier; reason: string },\n\tpreviousTier: ComplexityTier | undefined,\n): { tier: ComplexityTier; reason: string } {\n\tif (previousTier === \"powerful\" && result.tier === \"fast\") {\n\t\treturn { tier: \"balanced\", reason: `${result.reason} (dampened from fast: previous turn was powerful)` };\n\t}\n\treturn result;\n}\n\n// ============================================================================\n// Model selection\n// ============================================================================\n\n/** Select the best model for a given complexity tier from available models. */\nexport function selectModelForTier(tier: ComplexityTier, config: SmartRouterConfig): Model<Api> {\n\tconst { availableModels, preferredModel } = config;\n\n\t// Partition models into tiers\n\tconst tierModels = availableModels.filter((m) => modelTier(m) === tier);\n\n\tif (tierModels.length === 0) {\n\t\t// Requested tier has no models, fall back to preferred\n\t\treturn preferredModel;\n\t}\n\n\t// Pick the model with the largest context window (best value within tier)\n\tlet best = tierModels[0];\n\tfor (let i = 1; i < tierModels.length; i++) {\n\t\tif (tierModels[i].contextWindow > best.contextWindow) {\n\t\t\tbest = tierModels[i];\n\t\t}\n\t}\n\treturn best;\n}\n\n// ============================================================================\n// Main entry\n// ============================================================================\n\n/**\n * Analyze the turn and return a model recommendation.\n *\n * Returns undefined when:\n * - Smart routing is disabled\n * - The selected model is the same as the preferred model (no change needed)\n */\nexport function routeNextTurn(\n\tanalysis: TurnAnalysis,\n\tconfig: SmartRouterConfig,\n\tpreviousTier?: ComplexityTier,\n): SmartRouterResult | undefined {\n\tif (!config.enabled) return undefined;\n\n\tconst { tier, reason } = classifyComplexity(analysis, previousTier);\n\tconst model = selectModelForTier(tier, config);\n\n\t// No change needed if the router picks the same model the user already has\n\tif (modelsAreEqual(model, config.preferredModel)) return undefined;\n\n\treturn { model, tier, reason };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;IACjB,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;IACjB,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAwK3E","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.js\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.js\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write] */\n\tselectedTools?: string[];\n\t/** Optional one-line tool snippets keyed by tool name. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Additional guideline bullets appended to the default system prompt guidelines. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n\t/** Persistent codebase memory from previous sessions. */\n\tmemoryContent?: string;\n\t/** Detected technology stack summary (from stack-detector). */\n\tstackInfo?: string;\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t\tmemoryContent,\n\t\tstackInfo,\n\t} = options;\n\tconst resolvedCwd = cwd;\n\tconst promptCwd = resolvedCwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append stack info\n\t\tif (stackInfo) {\n\t\t\tprompt += \"\\n\\n# Technology Stack\\n\\n\";\n\t\t\tprompt += stackInfo;\n\t\t\tprompt += \"\\n\";\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append codebase memory\n\t\tif (memoryContent) {\n\t\t\tprompt += \"\\n\\n# Codebase Memory\\n\\n\";\n\t\t\tprompt += \"Knowledge from previous sessions on this project:\\n\\n\";\n\t\t\tprompt += memoryContent;\n\t\t\tprompt += \"\\n\";\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Add working directory last (date is injected via transformContext for cache stability)\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// A tool appears in Available tools only when the caller provides a one-line snippet.\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst visibleTools = tools.filter((name) => !!toolSnippets?.[name]);\n\tconst toolsList =\n\t\tvisibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets![name]}`).join(\"\\n\") : \"(none)\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\tconst hasRead = tools.includes(\"read\");\n\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\taddGuideline(\"Use bash for file operations like ls, rg, find\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\taddGuideline(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\n\t}\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\t// Always include these\n\taddGuideline(\"Be concise in your responses\");\n\taddGuideline(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are an expert coding assistant operating inside elyra, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nElyra documentation (read only when the user asks about elyra itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), elyra packages (docs/packages.md)\n- When working on elyra topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read elyra .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append stack info\n\tif (stackInfo) {\n\t\tprompt += \"\\n\\n# Technology Stack\\n\\n\";\n\t\tprompt += stackInfo;\n\t\tprompt += \"\\n\";\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append codebase memory\n\tif (memoryContent) {\n\t\tprompt += \"\\n\\n# Codebase Memory\\n\\n\";\n\t\tprompt += \"Knowledge from previous sessions on this project:\\n\\n\";\n\t\tprompt += memoryContent;\n\t\tprompt += \"\\n\";\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Add working directory last (date is injected via transformContext for cache stability)\n\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\treturn prompt;\n}\n"]}
|
|
@@ -8,11 +8,6 @@ export function buildSystemPrompt(options) {
|
|
|
8
8
|
const { customPrompt, selectedTools, toolSnippets, promptGuidelines, appendSystemPrompt, cwd, contextFiles: providedContextFiles, skills: providedSkills, memoryContent, stackInfo, } = options;
|
|
9
9
|
const resolvedCwd = cwd;
|
|
10
10
|
const promptCwd = resolvedCwd.replace(/\\/g, "/");
|
|
11
|
-
const now = new Date();
|
|
12
|
-
const year = now.getFullYear();
|
|
13
|
-
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
14
|
-
const day = String(now.getDate()).padStart(2, "0");
|
|
15
|
-
const date = `${year}-${month}-${day}`;
|
|
16
11
|
const appendSection = appendSystemPrompt ? `\n\n${appendSystemPrompt}` : "";
|
|
17
12
|
const contextFiles = providedContextFiles ?? [];
|
|
18
13
|
const skills = providedSkills ?? [];
|
|
@@ -47,8 +42,7 @@ export function buildSystemPrompt(options) {
|
|
|
47
42
|
if (customPromptHasRead && skills.length > 0) {
|
|
48
43
|
prompt += formatSkillsForPrompt(skills);
|
|
49
44
|
}
|
|
50
|
-
// Add date
|
|
51
|
-
prompt += `\nCurrent date: ${date}`;
|
|
45
|
+
// Add working directory last (date is injected via transformContext for cache stability)
|
|
52
46
|
prompt += `\nCurrent working directory: ${promptCwd}`;
|
|
53
47
|
return prompt;
|
|
54
48
|
}
|
|
@@ -138,8 +132,7 @@ Elyra documentation (read only when the user asks about elyra itself, its SDK, e
|
|
|
138
132
|
if (hasRead && skills.length > 0) {
|
|
139
133
|
prompt += formatSkillsForPrompt(skills);
|
|
140
134
|
}
|
|
141
|
-
// Add date
|
|
142
|
-
prompt += `\nCurrent date: ${date}`;
|
|
135
|
+
// Add working directory last (date is injected via transformContext for cache stability)
|
|
143
136
|
prompt += `\nCurrent working directory: ${promptCwd}`;
|
|
144
137
|
return prompt;
|
|
145
138
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.js\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.js\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write] */\n\tselectedTools?: string[];\n\t/** Optional one-line tool snippets keyed by tool name. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Additional guideline bullets appended to the default system prompt guidelines. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n\t/** Persistent codebase memory from previous sessions. */\n\tmemoryContent?: string;\n\t/** Detected technology stack summary (from stack-detector). */\n\tstackInfo?: string;\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t\tmemoryContent,\n\t\tstackInfo,\n\t} = options;\n\tconst resolvedCwd = cwd;\n\tconst promptCwd = resolvedCwd.replace(/\\\\/g, \"/\");\n\n\tconst now = new Date();\n\tconst year = now.getFullYear();\n\tconst month = String(now.getMonth() + 1).padStart(2, \"0\");\n\tconst day = String(now.getDate()).padStart(2, \"0\");\n\tconst date = `${year}-${month}-${day}`;\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append stack info\n\t\tif (stackInfo) {\n\t\t\tprompt += \"\\n\\n# Technology Stack\\n\\n\";\n\t\t\tprompt += stackInfo;\n\t\t\tprompt += \"\\n\";\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append codebase memory\n\t\tif (memoryContent) {\n\t\t\tprompt += \"\\n\\n# Codebase Memory\\n\\n\";\n\t\t\tprompt += \"Knowledge from previous sessions on this project:\\n\\n\";\n\t\t\tprompt += memoryContent;\n\t\t\tprompt += \"\\n\";\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Add date and working directory last\n\t\tprompt += `\\nCurrent date: ${date}`;\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// A tool appears in Available tools only when the caller provides a one-line snippet.\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst visibleTools = tools.filter((name) => !!toolSnippets?.[name]);\n\tconst toolsList =\n\t\tvisibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets![name]}`).join(\"\\n\") : \"(none)\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\tconst hasRead = tools.includes(\"read\");\n\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\taddGuideline(\"Use bash for file operations like ls, rg, find\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\taddGuideline(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\n\t}\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\t// Always include these\n\taddGuideline(\"Be concise in your responses\");\n\taddGuideline(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are an expert coding assistant operating inside elyra, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nElyra documentation (read only when the user asks about elyra itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), elyra packages (docs/packages.md)\n- When working on elyra topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read elyra .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append stack info\n\tif (stackInfo) {\n\t\tprompt += \"\\n\\n# Technology Stack\\n\\n\";\n\t\tprompt += stackInfo;\n\t\tprompt += \"\\n\";\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append codebase memory\n\tif (memoryContent) {\n\t\tprompt += \"\\n\\n# Codebase Memory\\n\\n\";\n\t\tprompt += \"Knowledge from previous sessions on this project:\\n\\n\";\n\t\tprompt += memoryContent;\n\t\tprompt += \"\\n\";\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Add date and working directory last\n\tprompt += `\\nCurrent date: ${date}`;\n\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\treturn prompt;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.js\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.js\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write] */\n\tselectedTools?: string[];\n\t/** Optional one-line tool snippets keyed by tool name. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Additional guideline bullets appended to the default system prompt guidelines. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n\t/** Persistent codebase memory from previous sessions. */\n\tmemoryContent?: string;\n\t/** Detected technology stack summary (from stack-detector). */\n\tstackInfo?: string;\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t\tmemoryContent,\n\t\tstackInfo,\n\t} = options;\n\tconst resolvedCwd = cwd;\n\tconst promptCwd = resolvedCwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append stack info\n\t\tif (stackInfo) {\n\t\t\tprompt += \"\\n\\n# Technology Stack\\n\\n\";\n\t\t\tprompt += stackInfo;\n\t\t\tprompt += \"\\n\";\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append codebase memory\n\t\tif (memoryContent) {\n\t\t\tprompt += \"\\n\\n# Codebase Memory\\n\\n\";\n\t\t\tprompt += \"Knowledge from previous sessions on this project:\\n\\n\";\n\t\t\tprompt += memoryContent;\n\t\t\tprompt += \"\\n\";\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Add working directory last (date is injected via transformContext for cache stability)\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// A tool appears in Available tools only when the caller provides a one-line snippet.\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst visibleTools = tools.filter((name) => !!toolSnippets?.[name]);\n\tconst toolsList =\n\t\tvisibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets![name]}`).join(\"\\n\") : \"(none)\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\tconst hasRead = tools.includes(\"read\");\n\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\taddGuideline(\"Use bash for file operations like ls, rg, find\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\taddGuideline(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\n\t}\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\t// Always include these\n\taddGuideline(\"Be concise in your responses\");\n\taddGuideline(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are an expert coding assistant operating inside elyra, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nElyra documentation (read only when the user asks about elyra itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), elyra packages (docs/packages.md)\n- When working on elyra topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read elyra .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append stack info\n\tif (stackInfo) {\n\t\tprompt += \"\\n\\n# Technology Stack\\n\\n\";\n\t\tprompt += stackInfo;\n\t\tprompt += \"\\n\";\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append codebase memory\n\tif (memoryContent) {\n\t\tprompt += \"\\n\\n# Codebase Memory\\n\\n\";\n\t\tprompt += \"Knowledge from previous sessions on this project:\\n\\n\";\n\t\tprompt += memoryContent;\n\t\tprompt += \"\\n\";\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Add working directory last (date is injected via transformContext for cache stability)\n\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\treturn prompt;\n}\n"]}
|
|
@@ -303,11 +303,13 @@ export declare class InteractiveMode {
|
|
|
303
303
|
*/
|
|
304
304
|
private showSelector;
|
|
305
305
|
private showSettingsSelector;
|
|
306
|
+
private handleHelpCommand;
|
|
306
307
|
private handleCostCommand;
|
|
307
308
|
private handleDiffCommand;
|
|
308
309
|
private handlePinCommand;
|
|
309
310
|
private handleUnpinCommand;
|
|
310
311
|
private handlePinsCommand;
|
|
312
|
+
private handleMemoryCommand;
|
|
311
313
|
private handleBlueprintCommand;
|
|
312
314
|
private handleFooterCommand;
|
|
313
315
|
private handleThemeCommand;
|