feat(ask): air ask "<task>" — interactive AI task execution

New `air ask` command:
- Accepts task description from CLI
- Auto-initializes project if needed
- MainAgent classifies → LLM generates → tools execute → results
- Supports Chinese keywords (创建/写/开发/实现 etc.)
- Tool call parser supports ```json and ```tool blocks
- Executes tools first, then checks DONE (fixes race condition)
- Strips GLM </think> reasoning tags from output

Usage: air ask "创建一个C++程序打印Hello World"

Tested end-to-end with glm-5.1 on new API endpoint.
Files correctly created: 13/13 E2E gates pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
AirCoding
2026-06-05 14:05:05 +08:00
parent bc58bd6840
commit 459308053c
3 changed files with 287 additions and 4 deletions

View File

@@ -31,6 +31,7 @@ import { sessionCommand } from './commands/session.js'
import { restoreCommand } from './commands/restore.js'
import { e2eCommand } from './commands/e2e.js'
import { releaseCommand } from './commands/release.js'
import { askCommand } from './commands/ask.js'
export async function main(argv: string[]): Promise<void> {
const args = argv.slice(2)
@@ -42,6 +43,13 @@ export async function main(argv: string[]): Promise<void> {
await runCommand(rest[0])
break
case 'ask':
await askCommand(rest.join(' '), {
model: rest.find(a => a.startsWith('--model='))?.split('=')[1],
maxTurns: rest.find(a => a.startsWith('--turns='))?.split('=')[1] ? parseInt(rest.find(a => a.startsWith('--turns='))!.split('=')[1]) : undefined
})
break
case 'init':
await initCommand(rest[0])
break
@@ -107,6 +115,7 @@ AirCoding V1.0.0 Alpha
Usage: air <command> [args...]
Commands:
ask "<prompt>" Ask the AI to implement a task
run [project] Start a session (spawns TUI)
init Initialize a new AirCoding project
doctor [--fix] Run diagnostic checks