iop/apps/node/internal/adapters/cli/antigravity_print.go

127 lines
3.6 KiB
Go

package cli
import (
"context"
"fmt"
"os"
"regexp"
"iop/apps/node/internal/runtime"
"iop/packages/go/config"
)
var antigravityConversationPatterns = []*regexp.Regexp{
regexp.MustCompile(`(?m)Created conversation (` + uuidPattern + `)`),
regexp.MustCompile(`(?m)Streaming conversation (` + uuidPattern + `)`),
regexp.MustCompile(`(?m)Print mode: conversation=(` + uuidPattern + `)`),
regexp.MustCompile(`(?m)conversationID="(` + uuidPattern + `)"`),
}
const uuidPattern = `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}`
func (c *CLI) executeAntigravityPrint(ctx context.Context, spec runtime.ExecutionSpec, profile config.CLIProfileConf, sink runtime.EventSink) error {
if len(profile.ResumeArgs) == 0 {
return fmt.Errorf("cli adapter: antigravity-print mode requires resume_args in profile %q", spec.Target)
}
sess, err := c.resolveAntigravitySession(spec)
if err != nil {
return err
}
sess.mu.Lock()
defer sess.mu.Unlock()
logFile, cleanup, err := createAntigravityLogFile()
if err != nil {
return err
}
defer cleanup()
prompt := extractPrompt(spec.Input)
args := antigravityPrintArgs(profile, sess.conversationID, logFile, prompt)
output, err := c.executeCommand(ctx, spec, profile, args, prompt, sink)
if err != nil {
return err
}
logOutput, readErr := os.ReadFile(logFile)
if readErr != nil {
return fmt.Errorf("cli adapter: read antigravity log: %w", readErr)
}
if conversationID := parseAntigravityConversationID(string(logOutput) + output); conversationID != "" {
sess.conversationID = conversationID
}
if sess.conversationID == "" {
return fmt.Errorf("cli adapter: antigravity-print did not report a conversation id")
}
return nil
}
func (c *CLI) resolveAntigravitySession(spec runtime.ExecutionSpec) (*antigravitySession, error) {
target := cliTargetName(spec)
key := sessionKey{target: target, sessionID: normalizeSessionID(spec.SessionID)}
c.mu.Lock()
defer c.mu.Unlock()
if sess, ok := c.agySessions[key]; ok {
return sess, nil
}
if spec.SessionMode == runtime.SessionModeRequireExisting {
return nil, fmt.Errorf("cli adapter: no antigravity conversation for target %q session %q", target, key.sessionID)
}
sess := &antigravitySession{key: key}
c.agySessions[key] = sess
return sess, nil
}
func antigravityPrintArgs(profile config.CLIProfileConf, conversationID, logFile, prompt string) []string {
args := []string{"--log-file", logFile}
if conversationID == "" {
args = append(args, profile.Args...)
} else {
args = append(args, removeAntigravityPrintFlag(profile.ResumeArgs)...)
args = append(args, conversationID)
args = append(args, "--print")
}
return append(args, prompt)
}
func removeAntigravityPrintFlag(args []string) []string {
filtered := make([]string, 0, len(args))
for _, arg := range args {
switch arg {
case "--print", "--prompt", "-p":
continue
default:
filtered = append(filtered, arg)
}
}
return filtered
}
func createAntigravityLogFile() (string, func(), error) {
f, err := os.CreateTemp("", "iop-antigravity-*.log")
if err != nil {
return "", nil, fmt.Errorf("cli adapter: create antigravity log file: %w", err)
}
path := f.Name()
if err := f.Close(); err != nil {
_ = os.Remove(path)
return "", nil, fmt.Errorf("cli adapter: close antigravity log file: %w", err)
}
return path, func() { _ = os.Remove(path) }, nil
}
func parseAntigravityConversationID(s string) string {
var id string
for _, re := range antigravityConversationPatterns {
for _, match := range re.FindAllStringSubmatch(s, -1) {
if len(match) >= 2 {
id = match[1]
}
}
}
return id
}