Files
ARTEX/db/intercept_execution.go
T
BaaRai e233c02314 Translate all Chinese text to English
Comments, doc comments, UI labels, log and error messages, LLM prompt
strings, markdown docs, test data and assertions. Identifiers, enum
keys, routes, placeholders and code structure are unchanged.

Notes:
- docs/漏洞流量证据.md renamed to docs/vulnerability-traffic-evidence.md
- tests that exercised CJK specific handling (GBK zip names, Chinese
  full text search) now use ASCII equivalents; go build passes and the
  test suite matches the pre translation baseline (remaining failures
  need a PostgreSQL DSN and fail identically on the original)
- frontend mention syntax now uses English kinds (finding, asset, ...)
  matching the backend, chat mentions tests pass
2026-10-08 23:14:34 +02:00

121 lines
4.2 KiB
Go

package db
import (
"errors"
"fmt"
"strconv"
)
var ErrInterceptTaskDeleted = errors.New("task has been deleted or archived")
var ErrInterceptSessionDeleted = errors.New("the corresponding session or execution record has been deleted or does not exist")
var ErrInterceptExecutionUnavailable = errors.New("no uniquely relatable original tool call found; the record may have been deleted, or a legacy approval did not store the correlation ID")
// InterceptExecution is a navigation target read from original activity rows.
// It is not model context and never falls back to matching command text.
type InterceptExecution struct {
ConversationID *int64 `json:"conversation_id,omitempty"`
TaskID *string `json:"task_id,omitempty"`
Session string `json:"session"`
Seq int64 `json:"seq"`
Items []Activity `json:"-"`
}
func (d *DB) GetInterceptExecution(id int64) (*InterceptExecution, error) {
approval, err := d.GetInterceptDetail(id)
if err != nil || approval == nil {
return nil, err
}
audit := approval.Audit
if audit == nil || audit.Correlation != "exact" || audit.ToolUseID == "" {
return nil, ErrInterceptExecutionUnavailable
}
var query string
var scope any
if approval.ConversationID != nil {
scope = *approval.ConversationID
query = `SELECT id, NULL::bigint, COALESCE(worker,''), kind, COALESCE(tool,''), tool_use_id, is_error, COALESCE(summary,''), created_at, NULL::integer FROM conversation_activities WHERE conversation_id=$1`
} else if approval.TaskID != nil {
taskID, parseErr := strconv.ParseInt(*approval.TaskID, 10, 64)
if parseErr != nil || taskID <= 0 {
return nil, ErrInterceptExecutionUnavailable
}
var exists bool
if err := d.QueryRow(`SELECT EXISTS(SELECT 1 FROM tasks WHERE id=$1 AND archived_at IS NULL AND deleted_at IS NULL)`, taskID).Scan(&exists); err != nil {
return nil, err
}
if !exists {
return nil, ErrInterceptTaskDeleted
}
scope = taskID
query = `SELECT id, node_id, COALESCE(worker,''), kind, COALESCE(tool,''), tool_use_id, is_error, COALESCE(summary,''), created_at, main_seg FROM activity WHERE exploration_id=(SELECT exploration_id FROM tasks WHERE id=$1 AND archived_at IS NULL AND deleted_at IS NULL)`
} else {
return nil, ErrInterceptExecutionUnavailable
}
// Three matches suffice to detect duplicate IDs without loading a transcript.
rows, err := d.Query(query+` AND tool_use_id=$2 AND kind IN ('tool_use','tool_result') ORDER BY id LIMIT 3`, scope, audit.ToolUseID)
if err != nil {
return nil, err
}
defer rows.Close()
out := &InterceptExecution{ConversationID: approval.ConversationID, TaskID: approval.TaskID}
for rows.Next() {
var a Activity
if err := rows.Scan(&a.ID, &a.NodeID, &a.Worker, &a.Kind, &a.Tool, &a.ToolUseID, &a.IsError, &a.Summary, &a.CreatedAt, &a.MainSeg); err != nil {
return nil, err
}
out.Items = append(out.Items, a)
}
if err := rows.Err(); err != nil {
return nil, err
}
if len(out.Items) == 0 {
return nil, ErrInterceptSessionDeleted
}
if len(out.Items) > 2 {
return nil, ErrInterceptExecutionUnavailable
}
call := out.Items[0]
if call.Kind != "tool_use" || call.Tool != approval.ToolName {
return nil, ErrInterceptExecutionUnavailable
}
if len(out.Items) == 2 {
result := out.Items[1]
if result.Kind != "tool_result" || result.Worker != call.Worker || (result.Tool != "" && result.Tool != call.Tool) || !sameOptionalInt64(call.NodeID, result.NodeID) || !sameMainSegment(call.MainSeg, result.MainSeg) {
return nil, ErrInterceptExecutionUnavailable
}
}
out.Seq = call.ID
if approval.ConversationID == nil {
switch {
case call.Worker == "mainagent":
seg := 0
if call.MainSeg != nil {
seg = *call.MainSeg
}
out.Session = fmt.Sprintf("main:%d", seg)
case call.Worker == "planner":
out.Session = "plan"
case call.NodeID != nil:
out.Session = fmt.Sprintf("intent:%d", *call.NodeID)
default:
return nil, ErrInterceptExecutionUnavailable
}
}
return out, nil
}
func sameOptionalInt64(a, b *int64) bool {
return (a == nil && b == nil) || (a != nil && b != nil && *a == *b)
}
func sameMainSegment(a, b *int) bool {
av, bv := 0, 0
if a != nil {
av = *a
}
if b != nil {
bv = *b
}
return av == bv
}