loopengine 0.1.37 → 0.1.38

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.
@@ -12,6 +12,11 @@ export interface AbilityEnvDecl {
12
12
  name: string;
13
13
  description?: string;
14
14
  secret?: boolean;
15
+ /** A closed set of valid values, e.g. `["openai", "google"]` for a
16
+ * provider switch — the Admin UI renders these as a dropdown instead
17
+ * of a free-text field. Omit for anything that isn't genuinely a fixed
18
+ * enum (an API key, a free-form model name, a path, ...). */
19
+ options?: string[];
15
20
  }
16
21
  /** `name`/`version` deliberately aren't declared here — they're read off
17
22
  * the ability's own sibling `package.json` instead (see readManifest),
@@ -1149,31 +1149,41 @@ export const agentsConfigPageHtml = `<!doctype html>
1149
1149
  : v.secret
1150
1150
  ? '<span class="hint">set</span>'
1151
1151
  : '<code>' + escapeHtml(v.value || '') + '</code>';
1152
+ // A var with a closed set of valid values (AbilityEnvDecl.options,
1153
+ // e.g. a provider switch) gets a <select> instead of a free-text
1154
+ // field, so there's nothing to mistype — the same "value" form field
1155
+ // name either element uses means wireEnvHandlers's own submit
1156
+ // handler doesn't need to know which one it's looking at.
1157
+ var fieldHtml = v.options
1158
+ ? '<select name="value">' + v.options.map(function (opt) {
1159
+ return '<option value="' + escapeHtml(opt) + '"' + (v.value === opt ? ' selected' : '') + '>' + escapeHtml(opt) + '</option>';
1160
+ }).join('') + '</select>'
1161
+ : '<input type="' + (v.secret ? 'password' : 'text') + '" name="value" placeholder="' + (v.set ? 'unchanged unless you type a new value' : 'value') + '" required>';
1152
1162
  return '<tr>' +
1153
1163
  '<td><code>' + escapeHtml(v.name) + '</code>' + sharedNote + '</td>' +
1154
1164
  '<td style="max-width:320px">' + escapeHtml(v.description || '') + '</td>' +
1155
1165
  '<td>' + statusHtml + '</td>' +
1156
1166
  '<td><form class="add-source env-var-form" data-name="' + escapeHtml(v.name) + '">' +
1157
- '<input type="' + (v.secret ? 'password' : 'text') + '" name="value" placeholder="' + (v.set ? 'unchanged unless you type a new value' : 'value') + '" required>' +
1167
+ fieldHtml +
1158
1168
  '<button type="submit">Save</button>' +
1159
1169
  '</form></td>' +
1160
1170
  '</tr>';
1161
1171
  }
1162
1172
 
1163
- // One card per ability, matching the same .source/.source-head/
1164
- // status-ok/status-error look Gateway Tools sources already use — so
1165
- // an operator scanning the tab sees, per ability, whether it's fully
1166
- // configured or not, instead of hunting through one long flat table
1167
- // for rows that belong to whichever ability they're actually trying to
1168
- // set up right now.
1173
+ // One card per ability, matching the same .source/.source-head look
1174
+ // Gateway Tools sources already use — so an operator scanning the tab
1175
+ // sees, per ability, which env vars it declared, instead of hunting
1176
+ // through one long flat table for rows that belong to whichever
1177
+ // ability they're actually trying to set up right now. Deliberately no
1178
+ // "not set" count here (or in renderEnvConfigHtml's own summary) — a
1179
+ // declared var not being set doesn't mean anything is broken, since
1180
+ // plenty of them have working defaults (see each var's own
1181
+ // description) and are only ever declared so an operator *can*
1182
+ // override them, not because every single one is required.
1169
1183
  function renderEnvAbilityCard(abilityName, vars) {
1170
- var missing = vars.filter(function (v) { return !v.set; }).length;
1171
- var statusHtml = missing === 0
1172
- ? '<span class="status-ok">all set</span>'
1173
- : '<span class="status-error">' + missing + ' of ' + vars.length + ' not set</span>';
1174
1184
  var rows = vars.map(renderEnvRow).join('');
1175
1185
  return '<div class="source">' +
1176
- '<div class="source-head"><h4>' + escapeHtml(abilityName) + '</h4>' + statusHtml + '</div>' +
1186
+ '<div class="source-head"><h4>' + escapeHtml(abilityName) + '</h4><span class="hint">' + vars.length + ' var' + (vars.length === 1 ? '' : 's') + '</span></div>' +
1177
1187
  '<table><thead><tr><th>Name</th><th style="max-width:320px">Description</th><th>Current value</th><th>Set value</th></tr></thead><tbody>' + rows + '</tbody></table>' +
1178
1188
  '</div>';
1179
1189
  }
@@ -1181,9 +1191,7 @@ export const agentsConfigPageHtml = `<!doctype html>
1181
1191
  function renderEnvConfigHtml(vars) {
1182
1192
  if (!vars.length) return '<p class="hint">No installed ability has declared any environment variables for this agent yet.</p>';
1183
1193
 
1184
- var missingCount = vars.filter(function (v) { return !v.set; }).length;
1185
- var summaryHtml = '<p class="hint">' + vars.length + ' environment variable' + (vars.length === 1 ? '' : 's') + ' across every installed ability' +
1186
- (missingCount ? ' — <span class="error">' + missingCount + ' still not set</span>.' : ' — all set.') + '</p>';
1194
+ var summaryHtml = '<p class="hint">' + vars.length + ' environment variable' + (vars.length === 1 ? '' : 's') + ' across every installed ability.</p>';
1187
1195
 
1188
1196
  // Grouped by declaring ability, not a single flat list — a var
1189
1197
  // declared by more than one ability (rare, but see renderEnvRow's
@@ -14,6 +14,10 @@ export interface DeclaredEnvVar {
14
14
  * web/http-tool-admin.ts's `{{ENV_VAR}}` header handling already
15
15
  * follow. Undefined whenever `secret` is true or `set` is false. */
16
16
  value?: string;
17
+ /** A closed set of valid values (see AbilityEnvDecl.options) — present
18
+ * only when the declaring ability actually named one; the Admin UI
19
+ * renders a dropdown instead of a free-text field when this is set. */
20
+ options?: string[];
17
21
  }
18
22
  /** Every env var any ability installed for `agentName` declared it
19
23
  * needs, merged by name. There's one .env per *project*, not per agent
@@ -65,6 +65,7 @@ export function listDeclaredEnvVars(agentName) {
65
65
  abilityNames: [abilityName],
66
66
  set: rawValue !== undefined,
67
67
  value: decl.secret === true ? undefined : rawValue,
68
+ options: decl.options,
68
69
  });
69
70
  }
70
71
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopengine",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "type": "module",
5
5
  "description": "Runtime for tool-using AI agents with a transparent ReAct loop.",
6
6
  "license": "MIT",