33 buildDocLink ,
44 type Config ,
55 defineCommand ,
6- detectOutputFormat ,
76 type GetModelsOptions ,
87 type GlobalFlags ,
98 getModels ,
@@ -14,6 +13,7 @@ import {
1413 type RecommendResult ,
1514 rankModels ,
1615 recallSemantic ,
16+ SEMANTIC_TOP_K ,
1717} from "bailian-cli-core" ;
1818import boxen from "boxen" ;
1919import chalk , { Chalk , type ChalkInstance } from "chalk" ;
@@ -229,14 +229,14 @@ export default defineCommand({
229229 } ,
230230 {
231231 flag : "--output <format>" ,
232- description : "Output format: text (default in TTY ), json, yaml " ,
232+ description : "Output format: json (default), rich (boxen cards) " ,
233233 } ,
234234 ] ,
235235 exampleArgs : [
236236 '--message "I need a visual-understanding chatbot"' ,
237237 '--message "Build an Agent that auto-generates animations"' ,
238238 '--message "Legal contract review, high precision required"' ,
239- '--message "Low-cost high-concurrency online customer service" --output json ' ,
239+ '--message "Low-cost high-concurrency online customer service" --output rich ' ,
240240 '--message "Long document summarization" --dry-run' ,
241241 " # Interactive input" ,
242242 ] ,
@@ -258,35 +258,77 @@ export default defineCommand({
258258 }
259259
260260 const top = 3 ;
261- const format = detectOutputFormat ( config . output ) ;
261+ // Default to JSON for structured output; only use rich (boxen cards) when explicitly requested
262+ const format = config . output === "rich" ? "rich" : "json" ;
263+
264+ // Stage 1: Intent Analysis + Model Loading (parallel)
265+ const spinner = createSpinner ( "Agent: Loading model data & analyzing intent..." ) ;
266+ spinner . start ( ) ;
262267
263268 const modelsOptions : GetModelsOptions = {
264- onPrepareStart : ( ) => process . stderr . write ( "Initializing model data...\n" ) ,
269+ onPrepareStart : ( ) => { } ,
265270 } ;
266- process . stderr . write ( "Analyzing your request...\n" ) ;
267- const [ allModels , intent ] = await Promise . all ( [
268- getModels ( config , modelsOptions ) ,
269- analyzeIntent ( config , userInput ) ,
270- ] ) ;
271+
272+ // Track individual completions for spinner updates
273+ let modelsReady = false ;
274+ let intentReady = false ;
275+
276+ const getModelsPromise = getModels ( config , modelsOptions ) . then ( ( result ) => {
277+ modelsReady = true ;
278+ if ( ! intentReady ) {
279+ spinner . update ( "Agent: Model data loaded, analyzing intent..." ) ;
280+ }
281+ return result ;
282+ } ) ;
283+
284+ const analyzeIntentPromise = analyzeIntent ( config , userInput ) . then ( ( result ) => {
285+ intentReady = true ;
286+ if ( ! modelsReady ) {
287+ spinner . update ( "Agent: Intent analyzed, loading model data..." ) ;
288+ }
289+ return result ;
290+ } ) ;
291+
292+ const [ allModels , intent ] = await Promise . all ( [ getModelsPromise , analyzeIntentPromise ] ) ;
293+
294+ spinner . stop ( ) ;
271295
272296 if ( intent . confidence === 0 ) {
273297 process . stderr . write ( "Intent analysis timed out, using defaults...\n" ) ;
274- } else {
275- process . stderr . write ( "\n" ) ;
276298 }
277299
278300 // Stage 2: Candidate Recall (semantic recall, auto-builds embeddings on first run)
279- const candidates = await recallSemantic ( config , allModels , userInput , 50 , intent ) ;
301+ spinner . update ( "Agent: Recalling candidates..." ) ;
302+ spinner . start ( ) ;
303+
304+ const candidates = await recallSemantic ( config , allModels , userInput , SEMANTIC_TOP_K , intent ) ;
305+
306+ spinner . stop ( ) ;
280307
281308 if ( config . dryRun ) {
282309 emitResult (
283310 {
284311 userInput,
285- intent,
312+ intent : {
313+ taskSummary : intent . taskSummary ,
314+ scenarioHints : intent . scenarioHints ,
315+ complexity : intent . complexity ,
316+ inputModality : intent . inputModality ,
317+ outputModality : intent . outputModality ,
318+ requiredCapabilities : intent . requiredCapabilities ,
319+ budget : intent . budget ,
320+ qualityPreference : intent . qualityPreference ,
321+ modelPreference :
322+ intent . modelPreference ?. mode !== "unconstrained" ? intent . modelPreference : undefined ,
323+ segments : intent . segments ,
324+ semanticQuery : intent . semanticQuery ,
325+ } ,
286326 candidateCount : candidates . length ,
287- candidates : candidates . map ( ( { model, score } ) => ( {
327+ candidates : candidates . map ( ( { model, score, hardScore , softScore } ) => ( {
288328 model : model . model ,
289329 score,
330+ hardScore,
331+ softScore,
290332 } ) ) ,
291333 top,
292334 } ,
@@ -296,7 +338,7 @@ export default defineCommand({
296338 }
297339
298340 // Stage 3: LLM Ranking
299- const spinner = createSpinner ( "Recommending best models...") ;
341+ spinner . update ( "Agent: Ranking models...") ;
300342 spinner . start ( ) ;
301343
302344 const result = await rankModels ( config , candidates , intent , userInput , top ) ;
@@ -308,7 +350,7 @@ export default defineCommand({
308350 return ;
309351 }
310352
311- if ( format !== "text " ) {
353+ if ( format !== "rich " ) {
312354 emitResult (
313355 {
314356 intent : {
@@ -323,6 +365,7 @@ export default defineCommand({
323365 modelPreference :
324366 intent . modelPreference ?. mode !== "unconstrained" ? intent . modelPreference : undefined ,
325367 segments : intent . segments ,
368+ semanticQuery : intent . semanticQuery ,
326369 } ,
327370 result,
328371 candidates : candidates . length ,
0 commit comments