-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathgh_copilot.js
More file actions
executable file
·136 lines (118 loc) · 3.92 KB
/
Copy pathgh_copilot.js
File metadata and controls
executable file
·136 lines (118 loc) · 3.92 KB
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/env node
// Combined GitHub Copilot CLI provider and grader for promptfoo
//
// Auto-detects mode based on prompt format:
// - Grader mode: Prompt is JSON array [{role, content}, ...]
// - Provider mode: Prompt is plain text
//
// Grader: Parses JSON chat array, concatenates system + user messages (no --system-prompt)
// Provider: Passes prompt directly to the copilot executable
const { spawnSync } = require('child_process');
// On Windows, .cmd files (like copilot.cmd) cannot be spawned directly by Node.js.
// Route through cmd.exe /c to resolve them without needing shell:true (which is
// deprecated when combined with an args array in Node v22+).
const IS_WIN = process.platform === 'win32';
function spawnCopilot(args, opts) {
const cmd = IS_WIN ? 'cmd.exe' : 'copilot';
const fullArgs = IS_WIN ? ['/c', 'copilot', ...args] : args;
return spawnSync(cmd, fullArgs, opts);
}
const prompt = process.argv[2];
const options = process.argv[3];
const context = process.argv[4];
// Detect mode: if prompt looks like a JSON array, use grader mode
let isGraderMode = false;
try {
const parsed = JSON.parse(prompt);
if (Array.isArray(parsed) && parsed.length > 0 && parsed[0].role) {
isGraderMode = true;
}
} catch (e) {
// Not JSON, so provider mode
}
if (isGraderMode) {
// ===== GRADER MODE =====
// Parse OPTIONS to get model from config
let model = ''; // Default to empty (no model flag)
if (options && options !== '{}') {
try {
const optionsObj = JSON.parse(options);
if (optionsObj.config && optionsObj.config.model) {
model = optionsObj.config.model;
}
} catch (e) {
// If JSON parsing fails, use default
model = '';
}
}
// Parse the JSON chat message array that promptfoo sends to graders
let systemMsg, userMsg;
try {
const messages = JSON.parse(prompt);
const systemMessage = messages.find(m => m.role === 'system');
const userMessage = messages.find(m => m.role === 'user');
if (systemMessage && userMessage) {
systemMsg = systemMessage.content;
userMsg = userMessage.content;
} else {
throw new Error('Missing system or user message');
}
} catch (e) {
// Fallback: treat the whole thing as a user message
systemMsg = 'You are an evaluator. Respond with only valid JSON: {"pass": bool, "score": 0.0-1.0, "reason": "string"}';
userMsg = prompt;
}
// Combine system and user into one prompt (copilot has no --system-prompt)
const fullPrompt = `${systemMsg}\n\n${userMsg}`;
// Build command with optional model flag
const args = ['--prompt', fullPrompt, '--allow-all-tools', '--silent'];
if (model) {
args.push('--model', model);
}
const result = spawnCopilot(args, {
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe']
});
if (result.error) {
console.error(result.error.message);
process.exit(1);
}
if (result.status !== 0) {
console.error(result.stdout || result.stderr);
process.exit(result.status || 1);
}
console.log(result.stdout);
} else {
// ===== PROVIDER MODE =====
// Parse OPTIONS to get model from config
let model = ''; // Default to empty (no model flag)
if (options && options !== '{}') {
try {
const optionsObj = JSON.parse(options);
if (optionsObj.config && optionsObj.config.model) {
model = optionsObj.config.model;
}
} catch (e) {
// If JSON parsing fails, use default
model = '';
}
}
// Build command with optional model flag
const args = ['--prompt', prompt, '--allow-all-tools', '--silent'];
if (model) {
args.push('--model', model);
}
const result = spawnCopilot(args, {
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe']
});
if (result.error) {
console.error(result.error.message);
process.exit(1);
}
if (result.status !== 0) {
console.error(result.stdout || result.stderr);
process.exit(result.status || 1);
}
console.log(result.stdout);
}