- edge node store 및 console 업데이트 - node adapters(cli, ollama, vllm, mock) 리팩토링 - node router, run_manager, store 개선 - proto 파일(control.proto, runtime.proto) 및 생성 코드 업데이트 - config 업데이트
88 lines
2.4 KiB
Go
88 lines
2.4 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"regexp"
|
|
|
|
"iop/apps/node/internal/runtime"
|
|
"iop/packages/config"
|
|
)
|
|
|
|
var (
|
|
codexSessionIDPattern = regexp.MustCompile(`(?mi)^session id:\s*(\S+)\s*$`)
|
|
codexThreadStartedRegex = regexp.MustCompile(`\{[^{}]*"type"\s*:\s*"thread\.started"[^{}]*\}`)
|
|
)
|
|
|
|
func (c *CLI) executeCodexExec(ctx context.Context, spec runtime.ExecutionSpec, profile config.CLIProfileConf, sink runtime.EventSink) error {
|
|
if profile.ResumeArgs == nil {
|
|
return fmt.Errorf("cli adapter: codex-exec mode requires resume_args in profile %q", spec.Target)
|
|
}
|
|
|
|
sess, err := c.resolveCodexExecSession(spec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sess.mu.Lock()
|
|
defer sess.mu.Unlock()
|
|
|
|
prompt := extractPrompt(spec.Input)
|
|
args := codexExecArgs(profile, sess.externalID, prompt)
|
|
output, err := c.executeCommand(ctx, spec, profile, args, prompt, sink)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if externalID := parseCodexSessionID(output); externalID != "" {
|
|
sess.externalID = externalID
|
|
}
|
|
if sess.externalID == "" {
|
|
return fmt.Errorf("cli adapter: codex exec did not report a session id")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *CLI) resolveCodexExecSession(spec runtime.ExecutionSpec) (*codexExecSession, error) {
|
|
agent := cliAgentName(spec)
|
|
key := sessionKey{agent: agent, sessionID: normalizeSessionID(spec.SessionID)}
|
|
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
if sess, ok := c.codexSessions[key]; ok {
|
|
return sess, nil
|
|
}
|
|
if spec.SessionMode == runtime.SessionModeRequireExisting {
|
|
return nil, fmt.Errorf("cli adapter: no persistent session for agent %q session %q", agent, key.sessionID)
|
|
}
|
|
sess := &codexExecSession{key: key}
|
|
c.codexSessions[key] = sess
|
|
return sess, nil
|
|
}
|
|
|
|
func codexExecArgs(profile config.CLIProfileConf, externalSessionID, prompt string) []string {
|
|
if externalSessionID == "" {
|
|
args := append([]string{}, profile.Args...)
|
|
return append(args, prompt)
|
|
}
|
|
args := append([]string{}, profile.ResumeArgs...)
|
|
return append(args, externalSessionID, prompt)
|
|
}
|
|
|
|
func parseCodexSessionID(output string) string {
|
|
if matches := codexSessionIDPattern.FindStringSubmatch(output); len(matches) >= 2 {
|
|
return matches[1]
|
|
}
|
|
for _, raw := range codexThreadStartedRegex.FindAllString(output, -1) {
|
|
var ev struct {
|
|
Type string `json:"type"`
|
|
ThreadID string `json:"thread_id"`
|
|
}
|
|
if err := json.Unmarshal([]byte(raw), &ev); err == nil && ev.Type == "thread.started" && ev.ThreadID != "" {
|
|
return ev.ThreadID
|
|
}
|
|
}
|
|
return ""
|
|
}
|