#643: Entscheidungen wecken den Agenten nur noch bei Ablehnung oder gescheiterter Ausfuehrung, gesammelt in einer Aufgabe je Agent (5 min Ruhefenster), frisch per @new:agent statt im fortgefuehrten Chatverlauf. Eine einmalige Aufgabe, deren Lauf wegen Budget oder Herunterfahren gar nicht stattfand, bleibt faellig (Wiedervorlage nach 30 min) statt mit gesetztem Marker liegenzubleiben. #641: Rechte stehen in der Werkzeugkonfiguration des Agenten (erlaubt/verboten). Erlaubtes laeuft, Nicht-Erlaubtes wird einzeln vorgelegt statt verweigert, Verbotenes gar nicht erst. "Gleichartiges kuenftig erlauben" erteilt eine widerrufbare Dauerfreigabe je Agent/Werkzeug/Operation; nach drei gleichartigen Freigaben schlaegt die Oberflaeche sie vor. Aenderungen an Agenten bleiben ausnahmslos freigabepflichtig. Database: Operation ist das SQL-Schluesselwort; die eigene Zugriffspruefung greift nur noch ohne Freigabestelle (AgentToolContext.FreigabeGeprueft). WebUI: Rechte-Tabelle je Werkzeug, Dauerfreigaben mit Widerruf. Version 0.1.11. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -411,19 +411,129 @@ async function zeigeWerkzeugEinstellungen(agentId, toolName) {
|
||||
box.append(
|
||||
erstelleElement("p", { klasse: "gedaempft", text: "Keine individuellen Einstellungen hinterlegt." })
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
const dl = erstelleElement("dl", { klasse: "datenliste" });
|
||||
for (const [schluessel, wert] of Object.entries(daten)) {
|
||||
const dt = erstelleElement("dt", { text: schluessel });
|
||||
const dd = erstelleElement("dd", { text: typeof wert === "object" ? JSON.stringify(wert) : String(wert) });
|
||||
dl.append(dt, dd);
|
||||
}
|
||||
box.append(dl);
|
||||
}
|
||||
|
||||
const dl = erstelleElement("dl", { klasse: "datenliste" });
|
||||
for (const [schluessel, wert] of Object.entries(daten)) {
|
||||
const dt = erstelleElement("dt", { text: schluessel });
|
||||
const dd = erstelleElement("dd", { text: typeof wert === "object" ? JSON.stringify(wert) : String(wert) });
|
||||
dl.append(dt, dd);
|
||||
}
|
||||
box.append(dl);
|
||||
} catch (err) {
|
||||
box.replaceChildren(
|
||||
erstelleElement("p", { klasse: "fehler", text: `Laden fehlgeschlagen: ${err.message}` })
|
||||
);
|
||||
}
|
||||
|
||||
const rechteBox = erstelleElement("div", { klasse: "einstellungen-box" });
|
||||
box.after(rechteBox);
|
||||
await zeigeWerkzeugrechte(agentId, toolName, rechteBox);
|
||||
}
|
||||
|
||||
const WIRKUNG = {
|
||||
auto: ["läuft", "erfolg"],
|
||||
approve: ["einzeln freigeben", "warnung"],
|
||||
deny: ["gesperrt", "gefahr"]
|
||||
};
|
||||
|
||||
/**
|
||||
* #641: Rechte je Operation. "erlaubt" laeuft ohne Rueckfrage, "freigabe" wird einzeln
|
||||
* vorgelegt, "verboten" gar nicht erst. Die Wirkung zeigt, was tatsaechlich geschieht -
|
||||
* auch durch Dauerfreigaben oder die Vorgabe des Werkzeugs.
|
||||
*/
|
||||
async function zeigeWerkzeugrechte(agentId, toolName, box) {
|
||||
const pfad = `/agents/${encodeURIComponent(agentId)}/tools/${encodeURIComponent(toolName)}/rights`;
|
||||
let rechte;
|
||||
try {
|
||||
rechte = await api(pfad);
|
||||
} catch (err) {
|
||||
box.replaceChildren(erstelleElement("p", { klasse: "gedaempft", text: `Rechte nicht lesbar: ${err.message}` }));
|
||||
return;
|
||||
}
|
||||
|
||||
box.replaceChildren(erstelleElement("h3", { text: "Rechte" }));
|
||||
|
||||
if (!rechte.operations || rechte.operations.length === 0) {
|
||||
box.append(
|
||||
erstelleElement("p", {
|
||||
klasse: "gedaempft",
|
||||
text: "Dieses Werkzeug kennt keine einzelnen Operationen. Es gilt die Standardregel."
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
box.append(
|
||||
erstelleElement("p", {
|
||||
klasse: "hinweis",
|
||||
text: rechte.configured
|
||||
? "Erlaubte Operationen laufen ohne Rückfrage, alle anderen werden einzeln zur Freigabe vorgelegt, verbotene gar nicht erst."
|
||||
: "Noch keine Rechte gesetzt: Es gilt die Vorgabe des Werkzeugs. Mit dem Speichern werden die Einstellungen unten verbindlich."
|
||||
})
|
||||
);
|
||||
|
||||
const tabelle = erstelleElement("table", { klasse: "daten-tabelle rechte-tabelle" });
|
||||
const kopf = erstelleElement("tr", {});
|
||||
for (const titel of ["Operation", "Einstellung", "Wirkung"]) {
|
||||
kopf.append(erstelleElement("th", { text: titel }));
|
||||
}
|
||||
tabelle.append(kopf);
|
||||
|
||||
const auswahl = new Map();
|
||||
for (const op of rechte.operations) {
|
||||
const select = erstelleElement(
|
||||
"select",
|
||||
{ disabled: op.alwaysApproval },
|
||||
erstelleElement("option", { value: "erlaubt", text: "erlaubt" }),
|
||||
erstelleElement("option", { value: "freigabe", text: "einzeln freigeben" }),
|
||||
erstelleElement("option", { value: "verboten", text: "verboten" })
|
||||
);
|
||||
// Ohne gesetzte Rechte die tatsaechliche Wirkung vorbelegen - sonst wuerde das erste
|
||||
// Speichern z.B. das freie Lesen still in eine Freigabepflicht verwandeln.
|
||||
select.value = rechte.configured
|
||||
? op.setting
|
||||
: op.effective === "auto" ? "erlaubt" : op.effective === "deny" ? "verboten" : "freigabe";
|
||||
auswahl.set(op.operation, select);
|
||||
|
||||
const [wirkungText, wirkungArt] = WIRKUNG[op.effective] ?? [op.effective, "neutral"];
|
||||
const wirkung = erstelleElement("td", {}, erstellePlakette(wirkungText, wirkungArt));
|
||||
if (op.standingApprovalId) {
|
||||
wirkung.append(" ", erstellePlakette(`Dauerfreigabe #${op.standingApprovalId}`, "neutral"));
|
||||
}
|
||||
wirkung.append(erstelleElement("div", {
|
||||
klasse: "grund",
|
||||
text: op.alwaysApproval ? "Änderungen an Agenten brauchen immer eine Freigabe." : op.reason
|
||||
}));
|
||||
|
||||
const zeile = erstelleElement("tr", {});
|
||||
zeile.append(erstelleElement("td", { text: op.operation }), erstelleElement("td", {}, select), wirkung);
|
||||
tabelle.append(zeile);
|
||||
}
|
||||
box.append(tabelle);
|
||||
|
||||
const speichern = erstelleElement("button", {
|
||||
type: "button",
|
||||
klasse: "schaltflaeche primaer klein",
|
||||
text: "Rechte speichern",
|
||||
onclick: async () => {
|
||||
const allowed = [];
|
||||
const denied = [];
|
||||
for (const [operation, select] of auswahl) {
|
||||
if (select.disabled) continue;
|
||||
if (select.value === "erlaubt") allowed.push(operation);
|
||||
if (select.value === "verboten") denied.push(operation);
|
||||
}
|
||||
speichern.disabled = true;
|
||||
try {
|
||||
const res = await api(pfad, { method: "PUT", body: { allowed, denied } });
|
||||
zeigeMeldung(res?.message ?? "Rechte gespeichert.", "erfolg");
|
||||
await zeigeWerkzeugrechte(agentId, toolName, box);
|
||||
} catch (err) {
|
||||
zeigeMeldung(`Speichern fehlgeschlagen: ${err.message}`, "gefahr");
|
||||
speichern.disabled = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
box.append(speichern);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user