create-loopengine 0.1.34 → 0.1.36
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.
- package/package.json +1 -1
- package/template/adapters/http.ts +50 -0
package/package.json
CHANGED
|
@@ -96,11 +96,13 @@ import {
|
|
|
96
96
|
ActauthRuleExistsError,
|
|
97
97
|
ActauthRuleNotFoundError,
|
|
98
98
|
installAbility,
|
|
99
|
+
upgradeAbility,
|
|
99
100
|
listInstalledAbilities,
|
|
100
101
|
AbilityAlreadyInstalledError,
|
|
101
102
|
AbilityCollisionError,
|
|
102
103
|
AbilityManifestError,
|
|
103
104
|
AbilityVersionError,
|
|
105
|
+
AbilityNotInstalledError,
|
|
104
106
|
searchPublicAbilities,
|
|
105
107
|
describeModelProviders,
|
|
106
108
|
describeGateways,
|
|
@@ -975,6 +977,17 @@ async function handleEnvPut(req: IncomingMessage, res: ServerResponse, agentName
|
|
|
975
977
|
res.writeHead(400, { 'content-type': 'application/json' }).end(JSON.stringify({ error: 'value is required' }))
|
|
976
978
|
return
|
|
977
979
|
}
|
|
980
|
+
// A dropdown-backed var (AbilityEnvDecl.options) is still writable
|
|
981
|
+
// through this same raw route — worth rejecting an out-of-set value
|
|
982
|
+
// here too, not just skipping validation because the Admin UI's own
|
|
983
|
+
// <select> would never have produced one.
|
|
984
|
+
const declared = listDeclaredEnvVars(agentName).find((v) => v.name === varName)
|
|
985
|
+
if (declared?.options && !declared.options.includes(body.value)) {
|
|
986
|
+
res.writeHead(400, { 'content-type': 'application/json' }).end(
|
|
987
|
+
JSON.stringify({ error: `"${body.value}" isn't one of this var's allowed values: ${declared.options.join(', ')}` }),
|
|
988
|
+
)
|
|
989
|
+
return
|
|
990
|
+
}
|
|
978
991
|
try {
|
|
979
992
|
setEnvVar(varName, body.value)
|
|
980
993
|
} catch (err) {
|
|
@@ -1054,6 +1067,38 @@ async function handleAbilityInstallPost(req: IncomingMessage, res: ServerRespons
|
|
|
1054
1067
|
}
|
|
1055
1068
|
}
|
|
1056
1069
|
|
|
1070
|
+
// Upgrades an already-installed ability to whatever it currently
|
|
1071
|
+
// resolves to (or, optionally, a specific spec) — same admin-auth
|
|
1072
|
+
// posture as handleAbilityInstallPost above, since this runs arbitrary
|
|
1073
|
+
// third-party code inside the agent's project the next time it's
|
|
1074
|
+
// loaded, same as install does.
|
|
1075
|
+
async function handleAbilityUpgradePost(req: IncomingMessage, res: ServerResponse, agentName: string, abilityName: string): Promise<void> {
|
|
1076
|
+
if (!adminAuth) {
|
|
1077
|
+
res.writeHead(403, { 'content-type': 'application/json' }).end(
|
|
1078
|
+
JSON.stringify({ error: 'Refusing to upgrade an ability without LOOPENGINE_ADMIN_AUTH configured — set it before upgrading abilities through this route.' }),
|
|
1079
|
+
)
|
|
1080
|
+
return
|
|
1081
|
+
}
|
|
1082
|
+
if (!getEntry(agentName)) {
|
|
1083
|
+
res.writeHead(404, { 'content-type': 'application/json' }).end(JSON.stringify({ error: `unknown agent '${agentName}'` }))
|
|
1084
|
+
return
|
|
1085
|
+
}
|
|
1086
|
+
const body = await readJsonBody(req)
|
|
1087
|
+
const spec = typeof body.spec === 'string' && body.spec ? body.spec : undefined
|
|
1088
|
+
try {
|
|
1089
|
+
const result = await upgradeAbility(agentName, abilityName, spec ? { spec } : {})
|
|
1090
|
+
res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(result))
|
|
1091
|
+
} catch (err) {
|
|
1092
|
+
const status =
|
|
1093
|
+
err instanceof AbilityNotInstalledError
|
|
1094
|
+
? 404
|
|
1095
|
+
: err instanceof AbilityManifestError || err instanceof AbilityVersionError
|
|
1096
|
+
? 422
|
|
1097
|
+
: 500
|
|
1098
|
+
res.writeHead(status, { 'content-type': 'application/json' }).end(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }))
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1057
1102
|
// Backs the Actauth tab's rule editor — parses a rule body shared by both
|
|
1058
1103
|
// the add (POST) and update (PUT, minus `name`) routes below.
|
|
1059
1104
|
function parseActauthRuleBody(body: Record<string, unknown>, requireName: boolean): { ok: true; value: { name: string; scope: string; tool: string; decision: Decision } } | { ok: false; error: string } {
|
|
@@ -2232,6 +2277,11 @@ const server = createServer(async (req, res) => {
|
|
|
2232
2277
|
await handleAbilitiesSearchGet(res, decodeURIComponent(abilitiesSearchMatch[1]), query)
|
|
2233
2278
|
return
|
|
2234
2279
|
}
|
|
2280
|
+
const abilityUpgradeMatch = pathname.match(/^\/agents\/([^/]+)\/abilities\/([^/]+)\/upgrade$/)
|
|
2281
|
+
if (abilityUpgradeMatch && req.method === 'POST') {
|
|
2282
|
+
await handleAbilityUpgradePost(req, res, decodeURIComponent(abilityUpgradeMatch[1]), decodeURIComponent(abilityUpgradeMatch[2]))
|
|
2283
|
+
return
|
|
2284
|
+
}
|
|
2235
2285
|
const abilitiesMatch = pathname.match(/^\/agents\/([^/]+)\/abilities$/)
|
|
2236
2286
|
if (abilitiesMatch && req.method === 'GET') {
|
|
2237
2287
|
handleAbilitiesGet(res, decodeURIComponent(abilitiesMatch[1]))
|