completion-kit 0.29.0 → 0.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +48 -3
- data/app/assets/javascripts/completion_kit/application.js +383 -0
- data/app/controllers/completion_kit/mcp_controller.rb +4 -0
- data/app/models/completion_kit/dataset.rb +53 -4
- data/app/models/completion_kit/metric.rb +1 -1
- data/app/models/completion_kit/prompt.rb +8 -0
- data/app/models/completion_kit/run.rb +1 -1
- data/app/services/completion_kit/api_config.rb +2 -1
- data/app/services/completion_kit/checks/regex.rb +12 -2
- data/app/services/completion_kit/csv_processor.rb +14 -2
- data/app/services/completion_kit/model_discovery_service.rb +2 -1
- data/app/services/completion_kit/ollama_client.rb +19 -2
- data/app/services/completion_kit/provider_endpoint.rb +10 -0
- data/app/views/completion_kit/api_reference/_authentication.html.erb +2 -2
- data/app/views/completion_kit/api_reference/_body.html.erb +0 -27
- data/app/views/completion_kit/api_reference/_example.html.erb +1 -1
- data/app/views/completion_kit/api_reference/_resource_card.html.erb +1 -1
- data/app/views/completion_kit/datasets/_form.html.erb +0 -28
- data/app/views/completion_kit/datasets/index.html.erb +1 -1
- data/app/views/completion_kit/metric_groups/_form.html.erb +1 -20
- data/app/views/completion_kit/metric_groups/index.html.erb +1 -1
- data/app/views/completion_kit/metrics/_starter_card.html.erb +1 -1
- data/app/views/completion_kit/metrics/index.html.erb +2 -2
- data/app/views/completion_kit/metrics/show.html.erb +4 -14
- data/app/views/completion_kit/prompts/_form.html.erb +1 -1
- data/app/views/completion_kit/prompts/index.html.erb +3 -3
- data/app/views/completion_kit/prompts/show.html.erb +8 -8
- data/app/views/completion_kit/provider_credentials/_models_card.html.erb +2 -2
- data/app/views/completion_kit/runs/_form.html.erb +3 -179
- data/app/views/completion_kit/runs/_response_row.html.erb +2 -3
- data/app/views/completion_kit/runs/_row.html.erb +3 -3
- data/app/views/completion_kit/runs/_run_config.html.erb +1 -1
- data/app/views/completion_kit/runs/show.html.erb +5 -19
- data/app/views/completion_kit/tags/index.html.erb +1 -1
- data/app/views/layouts/completion_kit/application.html.erb +2 -2
- data/lib/completion_kit/version.rb +1 -1
- data/lib/completion_kit.rb +14 -0
- data/lib/generators/completion_kit/templates/initializer.rb +18 -0
- metadata +1 -1
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
<div class="ck-select-with-action">
|
|
101
101
|
<%= form.select :judge_model, ck_grouped_models(available, run.judge_model, rejected: run.errors[:judge_model].any?), { include_blank: "None" }, { class: "ck-input", id: "run_judge_model", **ck_field_aria(form, :judge_model) } %>
|
|
102
102
|
<% ck_refreshing = CompletionKit::ProviderCredential.discovery_in_progress? %>
|
|
103
|
-
<button type="button" class="ck-icon-btn<%= ' ck-icon-btn--spinning' if ck_refreshing %>" title="Refresh models" <%= 'disabled' if ck_refreshing %>
|
|
103
|
+
<button type="button" class="ck-icon-btn<%= ' ck-icon-btn--spinning' if ck_refreshing %>" title="Refresh models" <%= 'disabled' if ck_refreshing %> data-ck-refresh-models><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" width="16" height="16"><path fill-rule="evenodd" d="M13.836 2.477a.75.75 0 0 1 .75.75v3.182a.75.75 0 0 1-.75.75h-3.182a.75.75 0 0 1 0-1.5h1.37l-.84-.841a4.5 4.5 0 0 0-7.08.681.75.75 0 0 1-1.264-.808 6 6 0 0 1 9.44-.908l.84.84V3.227a.75.75 0 0 1 .75-.75Zm-.911 7.5A.75.75 0 0 1 13.199 11a6 6 0 0 1-9.44.908l-.84-.84v1.68a.75.75 0 0 1-1.5 0V9.567a.75.75 0 0 1 .75-.75h3.182a.75.75 0 0 1 0 1.5h-1.37l.84.841a4.5 4.5 0 0 0 7.08-.681.75.75 0 0 1 1.024-.274Z" clip-rule="evenodd"/></svg></button>
|
|
104
104
|
</div>
|
|
105
105
|
<%= ck_field_error(form, :judge_model) %>
|
|
106
106
|
<p class="ck-field-hint" id="judge-hint"></p>
|
|
@@ -132,8 +132,7 @@
|
|
|
132
132
|
<button type="button"
|
|
133
133
|
class="ck-metric-group-pill"
|
|
134
134
|
data-metric-group
|
|
135
|
-
data-metric-ids="<%= g.metric_ids.join(",") %>"
|
|
136
|
-
onclick="ckToggleMetricGroup(this)">
|
|
135
|
+
data-metric-ids="<%= g.metric_ids.join(",") %>">
|
|
137
136
|
<span class="ck-metric-group-pill__check" aria-hidden="true">✓</span>
|
|
138
137
|
<span class="ck-metric-group-pill__label"><%= g.name %></span>
|
|
139
138
|
<span class="ck-metric-group-pill__count"><%= g.metric_ids.size %></span>
|
|
@@ -152,8 +151,7 @@
|
|
|
152
151
|
<button type="button"
|
|
153
152
|
class="tag-mark tag-mark--off ck-metric-tag-filter__chip"
|
|
154
153
|
style="--mark-color: var(--tag-<%= tag.color %>);"
|
|
155
|
-
data-filter-tag="<%= tag.name %>"
|
|
156
|
-
onclick="ckToggleMetricGroupFilter(this)"><%= tag.name %></button>
|
|
154
|
+
data-filter-tag="<%= tag.name %>"><%= tag.name %></button>
|
|
157
155
|
<% end %>
|
|
158
156
|
</div>
|
|
159
157
|
<% end %>
|
|
@@ -181,180 +179,6 @@
|
|
|
181
179
|
<% end %>
|
|
182
180
|
</div>
|
|
183
181
|
|
|
184
|
-
<script>
|
|
185
|
-
function updateRunForm() {
|
|
186
|
-
var promptEl = document.getElementById('run_prompt_id');
|
|
187
|
-
var judgeEl = document.getElementById('run_judge_model');
|
|
188
|
-
var judgeOnlyEl = document.getElementById('run_judge_only');
|
|
189
|
-
var judgeOnly = !!(judgeOnlyEl && judgeOnlyEl.checked);
|
|
190
|
-
var promptField = document.getElementById('prompt-field');
|
|
191
|
-
var outputColumnField = document.getElementById('output-column-field');
|
|
192
|
-
var outputColumnEl = document.getElementById('run_output_column');
|
|
193
|
-
if (promptField) promptField.hidden = judgeOnly;
|
|
194
|
-
if (outputColumnField) outputColumnField.hidden = !judgeOnly;
|
|
195
|
-
if (judgeOnly && promptEl) promptEl.value = '';
|
|
196
|
-
|
|
197
|
-
var prompt = promptEl ? promptEl.value : '';
|
|
198
|
-
var judge = judgeEl ? judgeEl.value : '';
|
|
199
|
-
var judgeListed = !!judgeEl && judgeEl.type !== 'hidden';
|
|
200
|
-
var metrics = document.querySelectorAll('input[name="run[metric_ids][]"]:checked');
|
|
201
|
-
var judgeField = document.getElementById('judge-field');
|
|
202
|
-
var metricsField = document.getElementById('metrics-field');
|
|
203
|
-
var judgeHint = document.getElementById('judge-hint');
|
|
204
|
-
var metricsHint = document.getElementById('metrics-hint');
|
|
205
|
-
var submitBtn = document.getElementById('run-submit');
|
|
206
|
-
|
|
207
|
-
if (judgeField) judgeField.className = 'ck-field';
|
|
208
|
-
if (metricsField) metricsField.className = 'ck-field';
|
|
209
|
-
if (judgeHint) judgeHint.textContent = '';
|
|
210
|
-
if (metricsHint) metricsHint.textContent = '';
|
|
211
|
-
|
|
212
|
-
var judgedMetrics = Array.prototype.filter.call(metrics, function(cb) {
|
|
213
|
-
var lbl = cb.closest('[data-needs-judge]');
|
|
214
|
-
return !!lbl && lbl.dataset.needsJudge === '1';
|
|
215
|
-
});
|
|
216
|
-
var judgeUnpaired = judgeListed && !!judge && metrics.length === 0;
|
|
217
|
-
var metricsUnpaired = judgeListed && !judge && judgedMetrics.length > 0;
|
|
218
|
-
if (judgeListed && judge && metrics.length > 0 && judgedMetrics.length === 0) {
|
|
219
|
-
if (judgeHint) judgeHint.textContent = 'Checks need no judge, so this run will not use it.';
|
|
220
|
-
} else if (judgeListed && judge && metrics.length > 0) {
|
|
221
|
-
if (judgeHint) judgeHint.textContent = judgeOnly ? 'Existing outputs will be judged automatically.' : 'Responses will be generated then judged automatically.';
|
|
222
|
-
} else if (judgeUnpaired) {
|
|
223
|
-
if (judgeField) judgeField.className = 'ck-field ck-field--info';
|
|
224
|
-
if (metricsField) metricsField.className = 'ck-field ck-field--info';
|
|
225
|
-
if (metricsHint) metricsHint.textContent = 'Select at least one metric or group to enable judging.';
|
|
226
|
-
} else if (metricsUnpaired) {
|
|
227
|
-
if (judgeField) judgeField.className = 'ck-field ck-field--info';
|
|
228
|
-
if (judgeHint) judgeHint.textContent = 'Select a judge model to enable judging.';
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
var datasetEl = document.getElementById('run_dataset_id');
|
|
232
|
-
var datasetHint = document.getElementById('dataset-hint');
|
|
233
|
-
var datasetField = document.getElementById('dataset-field');
|
|
234
|
-
var dataset = datasetEl ? datasetEl.value : '';
|
|
235
|
-
var selectedOption = promptEl ? promptEl.options[promptEl.selectedIndex] : null;
|
|
236
|
-
var hasVars = selectedOption && selectedOption.dataset.hasVariables === '1';
|
|
237
|
-
var promptVars = (selectedOption && selectedOption.dataset.variables ? selectedOption.dataset.variables.split(/,\s*/) : []).filter(Boolean);
|
|
238
|
-
|
|
239
|
-
var missingVars = [];
|
|
240
|
-
if (hasVars && dataset && datasetEl) {
|
|
241
|
-
var datasetOption = datasetEl.options[datasetEl.selectedIndex];
|
|
242
|
-
var headers = (datasetOption && datasetOption.dataset.headers ? datasetOption.dataset.headers.split(/,\s*/) : []).filter(Boolean);
|
|
243
|
-
missingVars = promptVars.filter(function(v) { return headers.indexOf(v) === -1; });
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (datasetField) datasetField.className = 'ck-field';
|
|
247
|
-
if (datasetHint) datasetHint.textContent = '';
|
|
248
|
-
if (missingVars.length > 0) {
|
|
249
|
-
if (datasetField) datasetField.className = 'ck-field ck-field--error';
|
|
250
|
-
if (datasetHint) datasetHint.textContent = 'Dataset is missing ' + (missingVars.length === 1 ? 'column' : 'columns') + ' the prompt needs: ' + missingVars.join(', ');
|
|
251
|
-
} else if (hasVars && !dataset) {
|
|
252
|
-
if (datasetField) datasetField.className = 'ck-field ck-field--info';
|
|
253
|
-
if (datasetHint) datasetHint.textContent = 'This prompt uses variables. Select a dataset to provide values.';
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
var expectedWarn = document.getElementById('expected-column-warn');
|
|
257
|
-
var expectedField = document.getElementById('expected-column-field');
|
|
258
|
-
var expectedColEl = document.getElementById('run_expected_column');
|
|
259
|
-
if (expectedField) expectedField.className = 'ck-field';
|
|
260
|
-
if (expectedWarn) expectedWarn.textContent = '';
|
|
261
|
-
var wantsExpected = false;
|
|
262
|
-
document.querySelectorAll('input[name="run[metric_ids][]"]:checked').forEach(function(cb) {
|
|
263
|
-
var lbl = cb.closest('[data-compare-expected]');
|
|
264
|
-
if (lbl && lbl.dataset.compareExpected === '1') wantsExpected = true;
|
|
265
|
-
});
|
|
266
|
-
if (wantsExpected && dataset && datasetEl) {
|
|
267
|
-
var expOption = datasetEl.options[datasetEl.selectedIndex];
|
|
268
|
-
var expHeaders = (expOption && expOption.dataset.headers ? expOption.dataset.headers.split(/,\s*/) : []).filter(Boolean);
|
|
269
|
-
var expCol = ((expectedColEl && expectedColEl.value) || 'expected_output').trim();
|
|
270
|
-
if (expHeaders.indexOf(expCol) === -1) {
|
|
271
|
-
if (expectedField) expectedField.className = 'ck-field ck-field--error';
|
|
272
|
-
if (expectedWarn) expectedWarn.textContent = "A selected check grades against each row's expected value, but this dataset has no \"" + expCol + "\" column, so every row would fail. Add the column or point this at the right one.";
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
var summary = document.getElementById('prompt-summary');
|
|
277
|
-
if (summary) {
|
|
278
|
-
if (selectedOption && selectedOption.value) {
|
|
279
|
-
var desc = selectedOption.dataset.description || '';
|
|
280
|
-
var tmpl = selectedOption.dataset.templatePreview || '';
|
|
281
|
-
var descEl = document.getElementById('prompt-summary-description');
|
|
282
|
-
descEl.textContent = desc;
|
|
283
|
-
descEl.hidden = !desc;
|
|
284
|
-
document.getElementById('prompt-summary-template').textContent = tmpl;
|
|
285
|
-
summary.hidden = false;
|
|
286
|
-
} else {
|
|
287
|
-
summary.hidden = true;
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
var valid;
|
|
292
|
-
if (judgeOnly) {
|
|
293
|
-
valid = !!dataset;
|
|
294
|
-
if (dataset && datasetEl && outputColumnEl) {
|
|
295
|
-
var headersJudge = (datasetEl.options[datasetEl.selectedIndex] && datasetEl.options[datasetEl.selectedIndex].dataset.headers ? datasetEl.options[datasetEl.selectedIndex].dataset.headers.split(/,\s*/) : []).filter(Boolean);
|
|
296
|
-
var col = (outputColumnEl.value || 'actual_output').trim();
|
|
297
|
-
if (col === '' || headersJudge.indexOf(col) === -1) {
|
|
298
|
-
valid = false;
|
|
299
|
-
if (datasetField) datasetField.className = 'ck-field ck-field--error';
|
|
300
|
-
if (datasetHint) datasetHint.textContent = "Dataset has no \"" + col + "\" column. Pick a different output column or dataset.";
|
|
301
|
-
}
|
|
302
|
-
} else if (!dataset) {
|
|
303
|
-
if (datasetField) datasetField.className = 'ck-field ck-field--info';
|
|
304
|
-
if (datasetHint) datasetHint.textContent = 'Skip generation and score responses you already have from a dataset column. Works with rubric metrics or deterministic checks.';
|
|
305
|
-
}
|
|
306
|
-
} else {
|
|
307
|
-
valid = prompt !== '';
|
|
308
|
-
if (hasVars && !dataset) valid = false;
|
|
309
|
-
if (missingVars.length > 0) valid = false;
|
|
310
|
-
}
|
|
311
|
-
if (judgeUnpaired || metricsUnpaired) valid = false;
|
|
312
|
-
if (submitBtn) submitBtn.disabled = !valid;
|
|
313
|
-
|
|
314
|
-
ckUpdateMetricGroupsState();
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
function ckToggleMetricGroup(button) {
|
|
318
|
-
var ids = (button.getAttribute('data-metric-ids') || '').split(',').filter(Boolean);
|
|
319
|
-
var allChecked = ids.every(function(id) {
|
|
320
|
-
var cb = document.getElementById('run_metric_' + id);
|
|
321
|
-
return cb && cb.checked;
|
|
322
|
-
});
|
|
323
|
-
ids.forEach(function(id) {
|
|
324
|
-
var cb = document.getElementById('run_metric_' + id);
|
|
325
|
-
if (cb) cb.checked = !allChecked;
|
|
326
|
-
});
|
|
327
|
-
updateRunForm();
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
function ckUpdateMetricGroupsState() {
|
|
331
|
-
document.querySelectorAll('[data-metric-group]').forEach(function(btn) {
|
|
332
|
-
var ids = (btn.getAttribute('data-metric-ids') || '').split(',').filter(Boolean);
|
|
333
|
-
if (ids.length === 0) return;
|
|
334
|
-
var allChecked = ids.every(function(id) {
|
|
335
|
-
var cb = document.getElementById('run_metric_' + id);
|
|
336
|
-
return cb && cb.checked;
|
|
337
|
-
});
|
|
338
|
-
btn.classList.toggle('ck-metric-group-pill--active', allChecked);
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
var judgeEl = document.getElementById('run_judge_model');
|
|
343
|
-
var promptEl = document.getElementById('run_prompt_id');
|
|
344
|
-
var datasetEl = document.getElementById('run_dataset_id');
|
|
345
|
-
var judgeOnlyEl = document.getElementById('run_judge_only');
|
|
346
|
-
var outputColumnEl = document.getElementById('run_output_column');
|
|
347
|
-
if (judgeEl) judgeEl.addEventListener('change', updateRunForm);
|
|
348
|
-
if (promptEl) promptEl.addEventListener('change', updateRunForm);
|
|
349
|
-
if (datasetEl) datasetEl.addEventListener('change', updateRunForm);
|
|
350
|
-
if (judgeOnlyEl) judgeOnlyEl.addEventListener('change', updateRunForm);
|
|
351
|
-
if (outputColumnEl) outputColumnEl.addEventListener('input', updateRunForm);
|
|
352
|
-
document.querySelectorAll('input[name="run[metric_ids][]"]').forEach(function(cb) {
|
|
353
|
-
cb.addEventListener('change', updateRunForm);
|
|
354
|
-
});
|
|
355
|
-
updateRunForm();
|
|
356
|
-
</script>
|
|
357
|
-
|
|
358
182
|
<%= render "completion_kit/tags/picker", record: run, param_namespace: :run %>
|
|
359
183
|
|
|
360
184
|
<div class="ck-actions">
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<% clickable = response.terminal? %>
|
|
2
|
-
<tr id="response_<%= response.id %>"<% if clickable %>
|
|
2
|
+
<tr id="response_<%= response.id %>"<% if clickable %> data-ck-href="<%= run_response_path(run, response, sort: params[:sort]) %>" style="cursor: pointer;"<% end %>>
|
|
3
3
|
<td class="ck-response-cell__index"><% if clickable %><%= link_to index, run_response_path(run, response, sort: params[:sort]), class: "ck-record-name" %><% else %><%= index %><% end %></td>
|
|
4
4
|
<td class="ck-response-cell__text">
|
|
5
5
|
<% if response.status == "failed" %>
|
|
@@ -69,8 +69,7 @@
|
|
|
69
69
|
<%= button_to "Retry", retry_failures_run_path(run, only: response.id),
|
|
70
70
|
method: :post,
|
|
71
71
|
class: "ck-chip ck-chip--retry",
|
|
72
|
-
form_class: "inline-block"
|
|
73
|
-
onclick: "event.stopPropagation();" %>
|
|
72
|
+
form_class: "inline-block" %>
|
|
74
73
|
<% end %>
|
|
75
74
|
</td>
|
|
76
75
|
<td class="ck-results-table__arrow"><% if clickable %><span aria-hidden="true">→</span><% end %></td>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<tr
|
|
1
|
+
<tr data-ck-href="<%= ck_run_path(run) %>" style="cursor: pointer;">
|
|
2
2
|
<td>
|
|
3
3
|
<div class="ck-runs-table__identity">
|
|
4
4
|
<span class="ck-run-name">
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
</span>
|
|
9
9
|
<div class="ck-runs-table__config">
|
|
10
10
|
<% if run.prompt %>
|
|
11
|
-
<%= link_to run.prompt.name, ck_prompt_path(run.prompt), class: "ck-runs-table__config-link"
|
|
11
|
+
<%= link_to run.prompt.name, ck_prompt_path(run.prompt), class: "ck-runs-table__config-link" %>
|
|
12
12
|
<span class="ck-runs-table__version">v<%= run.prompt.version_number %></span>
|
|
13
13
|
<% else %>
|
|
14
14
|
<span class="ck-runs-table__version">Scoring only</span>
|
|
15
15
|
<% end %>
|
|
16
16
|
<% if run.dataset %>
|
|
17
17
|
<span class="ck-runs-table__sep">·</span>
|
|
18
|
-
<%= link_to run.dataset.name, ck_dataset_path(run.dataset), class: "ck-runs-table__config-link"
|
|
18
|
+
<%= link_to run.dataset.name, ck_dataset_path(run.dataset), class: "ck-runs-table__config-link" %>
|
|
19
19
|
<% end %>
|
|
20
20
|
</div>
|
|
21
21
|
<% if run.tags.any? %>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<span class="ck-run-config__dataset">
|
|
10
10
|
<%= link_to run.dataset.name, dataset_path(run.dataset), class: "ck-link" %>
|
|
11
11
|
<span class="ck-run-config__dataset-meta"><%= run.dataset.row_count %> rows</span>
|
|
12
|
-
<button type="button" class="ck-run-config__dataset-preview"
|
|
12
|
+
<button type="button" class="ck-run-config__dataset-preview" data-ck-dialog-open="dataset-preview-<%= run.id %>">Preview</button>
|
|
13
13
|
</span>
|
|
14
14
|
<% else %>
|
|
15
15
|
<span class="ck-run-config__none">None</span>
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
</div>
|
|
15
15
|
<% end %>
|
|
16
16
|
|
|
17
|
-
|
|
18
17
|
<% if CompletionKit.config.judge_agreement_enabled %>
|
|
19
18
|
<% stale_summary = @run.stale_review_summary %>
|
|
20
19
|
<% if stale_summary.any? %>
|
|
@@ -68,7 +67,7 @@
|
|
|
68
67
|
</div>
|
|
69
68
|
<p class="ck-prompt-preview__text" id="prompt_text"><%= @run.prompt.template %></p>
|
|
70
69
|
<% if @run.prompt.template.length > 200 %>
|
|
71
|
-
<button type="button" class="ck-disclosure-toggle" id="prompt_toggle" aria-expanded="false" aria-controls="prompt_text"
|
|
70
|
+
<button type="button" class="ck-disclosure-toggle" id="prompt_toggle" aria-expanded="false" aria-controls="prompt_text" data-ck-prompt-toggle><span>Show more</span></button>
|
|
72
71
|
<% end %>
|
|
73
72
|
</div>
|
|
74
73
|
<% else %>
|
|
@@ -81,14 +80,14 @@
|
|
|
81
80
|
<% end %>
|
|
82
81
|
|
|
83
82
|
<% if @run.dataset %>
|
|
84
|
-
<dialog id="dataset-preview-<%= @run.id %>" class="ck-modal" aria-labelledby="dataset-preview-title-<%= @run.id %>"
|
|
85
|
-
<article class="ck-modal__panel" tabindex="-1" autofocus
|
|
83
|
+
<dialog id="dataset-preview-<%= @run.id %>" class="ck-modal" aria-labelledby="dataset-preview-title-<%= @run.id %>" data-ck-dialog>
|
|
84
|
+
<article class="ck-modal__panel" tabindex="-1" autofocus>
|
|
86
85
|
<header class="ck-modal__header">
|
|
87
86
|
<div class="ck-modal__heading">
|
|
88
87
|
<h2 class="ck-modal__title" id="dataset-preview-title-<%= @run.id %>"><%= @run.dataset.name %></h2>
|
|
89
88
|
<span class="ck-modal__meta"><%= @run.dataset.row_count %> rows</span>
|
|
90
89
|
</div>
|
|
91
|
-
<button type="button" class="ck-modal__close" aria-label="Close"
|
|
90
|
+
<button type="button" class="ck-modal__close" aria-label="Close" data-ck-dialog-close>×</button>
|
|
92
91
|
</header>
|
|
93
92
|
<div class="ck-modal__body">
|
|
94
93
|
<%
|
|
@@ -168,18 +167,5 @@
|
|
|
168
167
|
<% end %>
|
|
169
168
|
|
|
170
169
|
<% if @run.status.in?(%w[pending running]) %>
|
|
171
|
-
<
|
|
172
|
-
(function() {
|
|
173
|
-
if (window.ckRunStatusPoll) clearInterval(window.ckRunStatusPoll);
|
|
174
|
-
var url = '<%= refresh_status_run_path(@run) %>';
|
|
175
|
-
var refresh = function() {
|
|
176
|
-
fetch(url, { headers: { Accept: 'text/vnd.turbo-stream.html' }, credentials: 'same-origin' })
|
|
177
|
-
.then(function(r) { return r.ok ? r.text() : null; })
|
|
178
|
-
.then(function(html) { if (html) Turbo.renderStreamMessage(html); })
|
|
179
|
-
.catch(function() {});
|
|
180
|
-
};
|
|
181
|
-
setTimeout(refresh, 1000);
|
|
182
|
-
window.ckRunStatusPoll = setInterval(refresh, 15000);
|
|
183
|
-
})();
|
|
184
|
-
</script>
|
|
170
|
+
<div hidden data-ck-run-status-url="<%= refresh_status_run_path(@run) %>"></div>
|
|
185
171
|
<% end %>
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
<% count = @tagging_counts.fetch(tag.id, 0) %>
|
|
26
26
|
<% by_type = @tagging_by_type.select { |(tid, _), _| tid == tag.id } %>
|
|
27
27
|
<% breakdown = by_type.map { |(_, type), n| pluralize(n, type.demodulize.titleize.downcase) }.join(" · ") %>
|
|
28
|
-
<tr
|
|
28
|
+
<tr data-ck-href="<%= edit_tag_path(tag) %>" style="cursor: pointer;">
|
|
29
29
|
<td><%= link_to edit_tag_path(tag), class: "ck-record-name" do %><span class="tag-mark tag-mark--lg" style="--mark-color: var(--tag-<%= tag.color %>);"><%= tag.name %></span><% end %></td>
|
|
30
30
|
<td data-label="Applied to" class="ck-meta-copy">
|
|
31
31
|
<% if count.zero? %>
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
<%= favicon_link_tag "completion_kit/favicon.ico" %>
|
|
10
10
|
<%= stylesheet_link_tag "completion_kit/application", media: "all" %>
|
|
11
|
-
<%= javascript_include_tag "turbo", type: "module" %>
|
|
12
|
-
<%= javascript_include_tag "completion_kit/application", defer: true %>
|
|
11
|
+
<%= javascript_include_tag "turbo", type: "module", nonce: true %>
|
|
12
|
+
<%= javascript_include_tag "completion_kit/application", defer: true, nonce: true %>
|
|
13
13
|
<%= action_cable_meta_tag %>
|
|
14
14
|
</head>
|
|
15
15
|
<body class="ck-app">
|
data/lib/completion_kit.rb
CHANGED
|
@@ -5,6 +5,8 @@ require "completion_kit/concurrency_check"
|
|
|
5
5
|
|
|
6
6
|
module CompletionKit
|
|
7
7
|
class Configuration
|
|
8
|
+
MIN_REGEX_TIMEOUT = 0.001
|
|
9
|
+
|
|
8
10
|
attr_accessor :openai_api_key, :anthropic_api_key, :ollama_api_key, :ollama_api_endpoint
|
|
9
11
|
attr_accessor :judge_model, :high_quality_threshold, :medium_quality_threshold
|
|
10
12
|
attr_accessor :username, :password, :auth_strategy, :api_token, :current_reviewer
|
|
@@ -12,6 +14,8 @@ module CompletionKit
|
|
|
12
14
|
attr_accessor :api_reference_authentication_partial
|
|
13
15
|
attr_accessor :runs_display_scope, :runs_display_footer_partial
|
|
14
16
|
attr_accessor :api_rate_limit, :web_rate_limit, :max_upload_bytes
|
|
17
|
+
attr_accessor :max_template_bytes
|
|
18
|
+
attr_reader :regex_timeout
|
|
15
19
|
attr_accessor :allow_loopback_endpoints
|
|
16
20
|
attr_accessor :judge_agreement_enabled
|
|
17
21
|
attr_accessor :judge_examples_from_reviews
|
|
@@ -31,6 +35,8 @@ module CompletionKit
|
|
|
31
35
|
@api_rate_limit = 120
|
|
32
36
|
@web_rate_limit = 300
|
|
33
37
|
@max_upload_bytes = 25 * 1024 * 1024
|
|
38
|
+
@max_template_bytes = 1024 * 1024
|
|
39
|
+
@regex_timeout = 1.0
|
|
34
40
|
|
|
35
41
|
@allow_loopback_endpoints = true
|
|
36
42
|
@judge_agreement_enabled = true
|
|
@@ -42,6 +48,14 @@ module CompletionKit
|
|
|
42
48
|
def tenant_scope_columns
|
|
43
49
|
@tenant_scope_columns ||= []
|
|
44
50
|
end
|
|
51
|
+
|
|
52
|
+
def regex_timeout=(seconds)
|
|
53
|
+
unless seconds.nil? || (seconds.is_a?(Numeric) && seconds.real? && seconds.finite? && seconds >= MIN_REGEX_TIMEOUT)
|
|
54
|
+
raise ArgumentError, "regex_timeout must be a finite number of seconds of at least #{MIN_REGEX_TIMEOUT}, or nil, got #{seconds.inspect}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
@regex_timeout = seconds
|
|
58
|
+
end
|
|
45
59
|
end
|
|
46
60
|
|
|
47
61
|
class << self
|
|
@@ -7,6 +7,11 @@ CompletionKit.configure do |config|
|
|
|
7
7
|
# config.anthropic_api_key = ENV['ANTHROPIC_API_KEY']
|
|
8
8
|
# config.ollama_api_key = ENV['OLLAMA_API_KEY']
|
|
9
9
|
# config.ollama_api_endpoint = ENV['OLLAMA_API_ENDPOINT']
|
|
10
|
+
#
|
|
11
|
+
# The Ollama key is sent only to the Ollama endpoint set here, or to
|
|
12
|
+
# http://localhost:11434/v1 when no endpoint is set and
|
|
13
|
+
# config.allow_loopback_endpoints is on (the default). A provider credential
|
|
14
|
+
# that points at any other endpoint gets no key unless it stores its own.
|
|
10
15
|
|
|
11
16
|
# 2. Dotenv (.env file):
|
|
12
17
|
# require 'dotenv/load'
|
|
@@ -59,4 +64,17 @@ CompletionKit.configure do |config|
|
|
|
59
64
|
# web_rate_limit. Both are enforced through Rails.cache.
|
|
60
65
|
# config.api_rate_limit = 120
|
|
61
66
|
# config.web_rate_limit = 300
|
|
67
|
+
|
|
68
|
+
# Input limits
|
|
69
|
+
# Largest dataset CSV or import file, in bytes.
|
|
70
|
+
# config.max_upload_bytes = 25 * 1024 * 1024
|
|
71
|
+
# Largest prompt template, in bytes.
|
|
72
|
+
# config.max_template_bytes = 1024 * 1024
|
|
73
|
+
# Seconds one regex check pattern may spend matching one row. A row that runs
|
|
74
|
+
# past it fails and says it timed out. If your app sets a shorter
|
|
75
|
+
# Regexp.timeout, that one applies instead. The limit is set on each pattern,
|
|
76
|
+
# so the process-wide Regexp.timeout is never changed. Use a finite number of
|
|
77
|
+
# seconds of at least 0.001, or nil to use only Regexp.timeout. Any other
|
|
78
|
+
# value, such as 0, raises an ArgumentError at boot.
|
|
79
|
+
# config.regex_timeout = 1.0
|
|
62
80
|
end
|