File size: 2,807 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
 * Portable AgentBridge configuration (Gap 4).
 *
 * Serialises the operator-tunable AgentBridge state — user bypass patterns,
 * custom hosts, and per-agent model mappings — into a versioned JSON blob so a
 * setup can be replicated across machines (ProxyBridge ships the same
 * import/export-rules portability). Defaults (bank/gov/okta bypass, etc.) live
 * in code and are intentionally NOT exported, so importing never duplicates or
 * fights them.
 */
import { z } from "zod";
import { getUserBypassPatterns, replaceUserBypassPatterns } from "@/lib/db/agentBridgeBypass";
import { listCustomHosts, addCustomHost } from "@/lib/db/inspectorCustomHosts";
import { getMappingsForAgent, setMappings } from "@/lib/db/agentBridgeMappings";
import { ALL_TARGETS } from "@/mitm/targets/index";

export const AgentBridgeConfigSchema = z.object({
  version: z.literal(1),
  bypassPatterns: z.array(z.string()),
  customHosts: z.array(
    z.object({
      host: z.string().min(1),
      kind: z.enum(["llm", "app", "custom"]).default("custom"),
      label: z.string().nullable().optional(),
    })
  ),
  agentMappings: z.record(
    z.string(),
    z.array(z.object({ source: z.string(), target: z.string() }))
  ),
});

export type AgentBridgeConfig = z.infer<typeof AgentBridgeConfigSchema>;

/** Read the current operator-tunable AgentBridge state into a portable blob. */
export function exportConfig(): AgentBridgeConfig {
  const customHosts = listCustomHosts().map((h) => ({
    host: h.host,
    kind: (h.kind as "llm" | "app" | "custom") ?? "custom",
    label: h.label ?? null,
  }));

  const agentMappings: Record<string, Array<{ source: string; target: string }>> = {};
  for (const target of ALL_TARGETS) {
    const rows = getMappingsForAgent(target.id);
    if (rows.length > 0) {
      agentMappings[target.id] = rows.map((r) => ({
        source: r.source_model,
        target: r.target_model,
      }));
    }
  }

  return {
    version: 1,
    bypassPatterns: getUserBypassPatterns(),
    customHosts,
    agentMappings,
  };
}

export interface ImportResult {
  bypassPatterns: number;
  customHosts: number;
  agents: number;
}

/** Apply a validated config to the DB. Bypass + mappings replace wholesale;
 * custom hosts are added idempotently (INSERT OR IGNORE). */
export function importConfig(config: AgentBridgeConfig): ImportResult {
  replaceUserBypassPatterns(config.bypassPatterns);

  for (const h of config.customHosts) {
    addCustomHost(h.host, h.kind, h.label ?? undefined);
  }

  for (const [agentId, mappings] of Object.entries(config.agentMappings)) {
    setMappings(agentId, mappings);
  }

  return {
    bypassPatterns: config.bypassPatterns.length,
    customHosts: config.customHosts.length,
    agents: Object.keys(config.agentMappings).length,
  };
}