feat(agentstack): add delegation authority checks (#87)

This commit is contained in:
Qyra-One 2026-07-01 04:14:40 -04:00 • committed by GitHub
parent c495041adb
commit 0bca203527
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 92 additions and 27 deletions

View file

@ -178,18 +178,46 @@ export class AgentStack {
return grant;
}
revokeDelegation(grantId: string): DelegationGrant {
const grant = this.delegations.get(grantId);
if (!grant) throw new Error(`Unknown delegation grant: ${grantId}`);
this.delegations.delete(grantId);
this.emit({ type: "delegation.revoked", grant });
return grant;
}
listTasks(filter?: { ownerDid?: string; assigneeDid?: string; status?: TaskStatus }): DidTask[] {
return [...this.tasks.values()].filter((task) => {
if (filter?.ownerDid && task.ownerDid !== filter.ownerDid) return false;
if (filter?.assigneeDid && task.assigneeDid !== filter.assigneeDid) return false;
revokeDelegation(grantId: string): DelegationGrant {
const grant = this.delegations.get(grantId);
if (!grant) throw new Error(`Unknown delegation grant: ${grantId}`);
this.delegations.delete(grantId);
this.emit({ type: "delegation.revoked", grant });
return grant;
}
listDelegations(filter?: {
ownerDid?: string;
agentDid?: string;
scope?: string;
activeAt?: string;
}): DelegationGrant[] {
return [...this.delegations.values()].filter((grant) => {
if (filter?.ownerDid && grant.ownerDid !== filter.ownerDid) return false;
if (filter?.agentDid && grant.agentDid !== filter.agentDid) return false;
if (filter?.scope && !this.grantAllowsScope(grant, filter.scope)) return false;
if (filter?.activeAt && !this.grantIsActive(grant, filter.activeAt)) return false;
return true;
});
}
hasDelegation(ownerDidValue: string, agentDidValue: string, scope: string, at: string = this.now()): boolean {
if (!parseDid(ownerDidValue)) throw new Error(`Invalid owner DID: ${ownerDidValue}`);
if (!this.agents.has(agentDidValue)) throw new Error(`Unknown agent: ${agentDidValue}`);
return (
this.listDelegations({
ownerDid: ownerDidValue,
agentDid: agentDidValue,
scope,
activeAt: at
}).length > 0
);
}
listTasks(filter?: { ownerDid?: string; assigneeDid?: string; status?: TaskStatus }): DidTask[] {
return [...this.tasks.values()].filter((task) => {
if (filter?.ownerDid && task.ownerDid !== filter.ownerDid) return false;
if (filter?.assigneeDid && task.assigneeDid !== filter.assigneeDid) return false;
if (filter?.status && task.status !== filter.status) return false;
return true;
});
@ -205,10 +233,18 @@ export class AgentStack {
private requireTask(id: string): DidTask {
const task = this.tasks.get(id);
if (!task) throw new Error(`Unknown task: ${id}`);
return task;
}
}
if (!task) throw new Error(`Unknown task: ${id}`);
return task;
}
private grantAllowsScope(grant: DelegationGrant, scope: string): boolean {
return grant.scopes.includes(scope) || grant.scopes.includes("*");
}
private grantIsActive(grant: DelegationGrant, at: string): boolean {
return !grant.expiresAt || grant.expiresAt > at;
}
}
/** LogicSRC plugin definition exposing AgentStack as a coordination plugin. */
export const agentStackPlugin: PluginDefinition = {