loopengine 0.1.42 → 0.1.44

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.
@@ -84,6 +84,20 @@ export interface InstalledAbilityRecord {
84
84
  export declare function listInstalledAbilities(agentName: string): Array<{
85
85
  name: string;
86
86
  } & InstalledAbilityRecord>;
87
+ /** `record.dependencies` is only ever absent for an ability installed or
88
+ * last upgraded before that field existed (see InstalledAbilityRecord's
89
+ * own doc comment) — this re-derives it once by refetching the ability's
90
+ * own manifest (same technique upgradeAbility already uses for its own
91
+ * three-way merge base) and persists the result into provenance, so this
92
+ * only ever runs once per such ability rather than on every read. A
93
+ * record that already has `dependencies` — even a real empty array,
94
+ * meaning the ability genuinely declares none — is returned unchanged,
95
+ * never refetched. Best-effort: a spec that no longer resolves (private
96
+ * registry auth expired, a git ref that's gone, ...) leaves
97
+ * `dependencies` unset rather than throwing, since the Admin UI's own
98
+ * caller (handleAbilitiesGet) would rather show "can't tell" than fail
99
+ * the whole abilities list over one ability's stale record. */
100
+ export declare function backfillDependencies(agentName: string, abilityName: string, options?: FetchOptions): Promise<string[] | undefined>;
87
101
  /** `npm pack <spec>` + tar extract — generalized from
88
102
  * create-loopengine's own `fetchPublishedTemplateDir` (that function
89
103
  * only ever fetches the hardcoded `create-loopengine@<version>`; this
@@ -166,6 +166,39 @@ export function listInstalledAbilities(agentName) {
166
166
  function writeProvenance(agentName, data) {
167
167
  writeFileSync(provenancePath(agentName), JSON.stringify(data, null, 2) + '\n');
168
168
  }
169
+ /** `record.dependencies` is only ever absent for an ability installed or
170
+ * last upgraded before that field existed (see InstalledAbilityRecord's
171
+ * own doc comment) — this re-derives it once by refetching the ability's
172
+ * own manifest (same technique upgradeAbility already uses for its own
173
+ * three-way merge base) and persists the result into provenance, so this
174
+ * only ever runs once per such ability rather than on every read. A
175
+ * record that already has `dependencies` — even a real empty array,
176
+ * meaning the ability genuinely declares none — is returned unchanged,
177
+ * never refetched. Best-effort: a spec that no longer resolves (private
178
+ * registry auth expired, a git ref that's gone, ...) leaves
179
+ * `dependencies` unset rather than throwing, since the Admin UI's own
180
+ * caller (handleAbilitiesGet) would rather show "can't tell" than fail
181
+ * the whole abilities list over one ability's stale record. */
182
+ export async function backfillDependencies(agentName, abilityName, options = {}) {
183
+ const provenance = readProvenance(agentName);
184
+ const record = provenance[abilityName];
185
+ if (!record)
186
+ return undefined;
187
+ if (record.dependencies !== undefined)
188
+ return record.dependencies;
189
+ const fetch = options.fetchAbilityDir ?? fetchAbilityDir;
190
+ try {
191
+ const dir = fetch(record.spec ?? abilityName);
192
+ const manifest = readManifest(dir);
193
+ record.dependencies = manifest.dependencies ?? [];
194
+ provenance[abilityName] = record;
195
+ writeProvenance(agentName, provenance);
196
+ return record.dependencies;
197
+ }
198
+ catch {
199
+ return undefined;
200
+ }
201
+ }
169
202
  function sha256(content) {
170
203
  return createHash('sha256').update(content).digest('hex');
171
204
  }
package/dist/index.d.ts CHANGED
@@ -57,7 +57,7 @@ export { listDeclaredEnvVars, setEnvVar, EnvVarNameError } from './web/env-admin
57
57
  export type { DeclaredEnvVar } from './web/env-admin.js';
58
58
  export { readActauthConfig, addActauthRule, updateActauthRule, removeActauthRule, setDefaultDecision, ActauthRuleExistsError, ActauthRuleNotFoundError, } from './web/actauth-admin.js';
59
59
  export type { ActauthRuleInput, ActauthConfigView } from './web/actauth-admin.js';
60
- export { installAbility, upgradeAbility, listInstalledAbilities, AbilityManifestError, AbilityVersionError, AbilityCollisionError, AbilityAlreadyInstalledError, AbilityNotInstalledError, } from './bin/ability-manager.js';
60
+ export { installAbility, upgradeAbility, listInstalledAbilities, backfillDependencies, AbilityManifestError, AbilityVersionError, AbilityCollisionError, AbilityAlreadyInstalledError, AbilityNotInstalledError, } from './bin/ability-manager.js';
61
61
  export type { InstalledAbilityRecord, AbilityEnvDecl, UpgradeFileResult } from './bin/ability-manager.js';
62
62
  export { searchPublicAbilities, fetchLatestAbilityVersion } from './web/abilities-admin.js';
63
63
  export type { PublicAbilitySearchResult } from './web/abilities-admin.js';
package/dist/index.js CHANGED
@@ -51,7 +51,7 @@ export { playgroundHtml } from './web/playground.js';
51
51
  export { readSkill, writeSkill, deleteSkill, SkillInvalidIdError, SkillNotFoundError } from './web/skills-admin.js';
52
52
  export { listDeclaredEnvVars, setEnvVar, EnvVarNameError } from './web/env-admin.js';
53
53
  export { readActauthConfig, addActauthRule, updateActauthRule, removeActauthRule, setDefaultDecision, ActauthRuleExistsError, ActauthRuleNotFoundError, } from './web/actauth-admin.js';
54
- export { installAbility, upgradeAbility, listInstalledAbilities, AbilityManifestError, AbilityVersionError, AbilityCollisionError, AbilityAlreadyInstalledError, AbilityNotInstalledError, } from './bin/ability-manager.js';
54
+ export { installAbility, upgradeAbility, listInstalledAbilities, backfillDependencies, AbilityManifestError, AbilityVersionError, AbilityCollisionError, AbilityAlreadyInstalledError, AbilityNotInstalledError, } from './bin/ability-manager.js';
55
55
  export { searchPublicAbilities, fetchLatestAbilityVersion } from './web/abilities-admin.js';
56
56
  export { describeModelProviders, describeGateways } from './web/global-config.js';
57
57
  export { createTrackedApprover, listApprovals, decideApproval, findApproval } from './web/web-approver.js';
@@ -75,15 +75,18 @@ export const agentsConfigPageHtml = `<!doctype html>
75
75
  flex-direction: column;
76
76
  }
77
77
  #agentList { list-style: none; margin: 0; padding: 6px; flex: 1; }
78
- #agentList li {
78
+ #agentList li { border-radius: 6px; }
79
+ #agentList li a {
80
+ display: block;
79
81
  padding: 8px 10px;
80
82
  border-radius: 6px;
81
- cursor: pointer;
82
83
  font-size: 13px;
83
84
  font-family: ui-monospace, monospace;
85
+ color: inherit;
86
+ text-decoration: none;
84
87
  }
85
- #agentList li:hover { background: light-dark(#eee, #26262b); }
86
- #agentList li.active { background: light-dark(#dbeafe, #1e3a5f); font-weight: 600; }
88
+ #agentList li a:hover { background: light-dark(#eee, #26262b); }
89
+ #agentList li.active a { background: light-dark(#dbeafe, #1e3a5f); font-weight: 600; }
87
90
  main {
88
91
  flex: 1;
89
92
  overflow-y: auto;
@@ -2512,9 +2515,17 @@ export const agentsConfigPageHtml = `<!doctype html>
2512
2515
  for (var i = 0; i < agents.length; i++) {
2513
2516
  (function (name) {
2514
2517
  var li = document.createElement('li');
2515
- li.textContent = name;
2516
2518
  li.dataset.name = name;
2517
- li.addEventListener('click', function () { selectAgent(name); });
2519
+ // A real <a href>, not a click handler calling selectAgent —
2520
+ // switching agents is a full navigation to this same page with
2521
+ // a different ?agent=, so the URL, browser back/forward, and
2522
+ // bookmarking all reflect which agent is open, instead of the
2523
+ // URL staying frozen at whatever it was on first load while
2524
+ // the panel silently swaps underneath it via fetch.
2525
+ var a = document.createElement('a');
2526
+ a.href = '/agents/config?agent=' + encodeURIComponent(name);
2527
+ a.textContent = name;
2528
+ li.appendChild(a);
2518
2529
  agentList.appendChild(li);
2519
2530
  })(agents[i].name);
2520
2531
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopengine",
3
- "version": "0.1.42",
3
+ "version": "0.1.44",
4
4
  "type": "module",
5
5
  "description": "Runtime for tool-using AI agents with a transparent ReAct loop.",
6
6
  "license": "MIT",
@@ -1,25 +0,0 @@
1
- ---
2
- name: composio-large-outputs
3
- description: How to retrieve a gateway tool's real output when its result says storedInFile is true instead of returning the data inline.
4
- ---
5
-
6
- # Gateway tools with a large result
7
-
8
- Some gateway tools (Composio-sourced ones in particular) return a small
9
- pointer object instead of their real output when the actual result is
10
- too large to return inline:
11
-
12
- ```
13
- {
14
- "successful": true,
15
- "storedInFile": true,
16
- "tokenCount": 10234,
17
- "outputFilePath": "/tmp/.../SOME_TOOL_OUTPUT_xxxxx.json"
18
- }
19
- ```
20
-
21
- When you see `storedInFile: true` in a tool result, the real data is
22
- **not** in that object — it's in the file at `outputFilePath`. Call
23
- `system_read_file` with that exact path to retrieve the actual content
24
- before answering. Don't guess at an answer, summarize from the pointer
25
- alone, or claim you don't have the data — read the file first.