@@ -98,6 +98,27 @@ func (c *Compiler) setupEngineAndImports(result *parser.FrontmatterResult, clean
9898 c .IncrementWarningCount ()
9999 }
100100 engineSetting = c .engineOverride
101+ // Update engineConfig.ID so that downstream code (e.g. generateCreateAwInfo) uses
102+ // the override engine ID, not the one parsed from the frontmatter.
103+ if engineConfig != nil {
104+ engineConfig .ID = c .engineOverride
105+ }
106+ }
107+
108+ // When the engine is specified in short/string form ("engine: copilot") and no CLI
109+ // override is active, inject the corresponding builtin shared-workflow .md as an
110+ // import. This makes "engine: copilot" syntactic sugar for importing the builtin
111+ // copilot.md, which carries the full engine definition. The engine field is removed
112+ // from the frontmatter so the definition comes entirely from the import.
113+ if c .engineOverride == "" && isStringFormEngine (result .Frontmatter ) && engineSetting != "" {
114+ builtinPath := builtinEnginePath (engineSetting )
115+ if parser .BuiltinVirtualFileExists (builtinPath ) {
116+ orchestratorEngineLog .Printf ("Injecting builtin engine import: %s" , builtinPath )
117+ addImportToFrontmatter (result .Frontmatter , builtinPath )
118+ delete (result .Frontmatter , "engine" )
119+ engineSetting = ""
120+ engineConfig = nil
121+ }
101122 }
102123
103124 // Process imports from frontmatter first (before @include directives)
@@ -197,6 +218,19 @@ func (c *Compiler) setupEngineAndImports(result *parser.FrontmatterResult, clean
197218 return nil , fmt .Errorf ("failed to extract engine config from included file: %w" , err )
198219 }
199220 engineConfig = extractedConfig
221+
222+ // If the imported engine is an inline definition (engine.runtime sub-object),
223+ // validate and register it in the catalog. This mirrors the handling for inline
224+ // definitions declared directly in the main workflow (above).
225+ if engineConfig != nil && engineConfig .IsInlineDefinition {
226+ if err := c .validateEngineInlineDefinition (engineConfig ); err != nil {
227+ return nil , err
228+ }
229+ if err := c .validateEngineAuthDefinition (engineConfig ); err != nil {
230+ return nil , err
231+ }
232+ c .registerInlineEngineDefinition (engineConfig )
233+ }
200234 }
201235
202236 // Apply the default AI engine setting if not specified
@@ -299,3 +333,43 @@ func (c *Compiler) setupEngineAndImports(result *parser.FrontmatterResult, clean
299333 configSteps : configSteps ,
300334 }, nil
301335}
336+
337+ // isStringFormEngine reports whether the "engine" field in the given frontmatter is a
338+ // plain string (e.g. "engine: copilot"), as opposed to an object with an "id" or
339+ // "runtime" sub-key.
340+ func isStringFormEngine (frontmatter map [string ]any ) bool {
341+ engine , exists := frontmatter ["engine" ]
342+ if ! exists {
343+ return false
344+ }
345+ _ , isString := engine .(string )
346+ return isString
347+ }
348+
349+ // addImportToFrontmatter appends importPath to the "imports" slice in frontmatter.
350+ // It handles the case where "imports" may be absent, a []any, a []string, or a
351+ // single string (which is converted to a two-element slice preserving the original value).
352+ // Any other unexpected type is left unchanged and importPath is not injected.
353+ func addImportToFrontmatter (frontmatter map [string ]any , importPath string ) {
354+ existing , hasImports := frontmatter ["imports" ]
355+ if ! hasImports {
356+ frontmatter ["imports" ] = []any {importPath }
357+ return
358+ }
359+ switch v := existing .(type ) {
360+ case []any :
361+ frontmatter ["imports" ] = append (v , importPath )
362+ case []string :
363+ newSlice := make ([]any , len (v )+ 1 )
364+ for i , s := range v {
365+ newSlice [i ] = s
366+ }
367+ newSlice [len (v )] = importPath
368+ frontmatter ["imports" ] = newSlice
369+ case string :
370+ // Single string import — preserve it and append the new one.
371+ frontmatter ["imports" ] = []any {v , importPath }
372+ // For any other unexpected type, leave the field untouched so the
373+ // downstream parser can still report its own error for the invalid value.
374+ }
375+ }
0 commit comments