agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
46 lines • 2.13 kB
JavaScript
/**
* verifiedThreads — the {@link ThreadBinder} that binds a thread to a VERIFIED
* caller, so the secure binding is the one-line one.
*
* A request names a thread; naming one proves nothing. This binder checks the
* caller's credential with the door's own identity verification
* (`verifyRequestIdentity` — the bearer token, through your verifier), never a
* header read as a name, and keys the conversation by WHO
* plus WHICH: the same thread id from two people is two conversations. The
* run's `identity` names the verified person, so a stored conversation records
* its owner and a later request from anyone else is refused as not found.
*
* A caller with no credential is REFUSED (401), even at a door that allows
* anonymous requests elsewhere: a thread with no owner would be anybody's who
* guessed its id.
*/
import { IdentityNotVerifiedError } from './errors.js';
import { verifyRequestIdentity } from './identityVerification.js';
/**
* Bind every thread to the caller `identity` verifies.
*
* @example
* ```ts
* import { jwksIdentity } from 'agentfootprint/security';
* const threads = verifiedThreads(jwksIdentity({ jwksUrl, issuer, audience }));
* streamHandler({ agent, adapter: agUi(), threads, sessions: memorySessions() });
* ```
*/
export function verifiedThreads(identity) {
const binder = {
async bind({ conversation, headers }) {
const who = await verifyRequestIdentity(identity, headers, undefined);
if (who === undefined)
throw new IdentityNotVerifiedError('no-token', false);
return {
// Injective, and visible ASCII whatever the name (`josé`, `John Smith`):
// both halves are percent-encoded, the separator included, so no
// (who, which) pair spells another's key.
sessionId: `${encodeURIComponent(who.userId)}/${encodeURIComponent(conversation)}`,
identity: { principal: who.userId, conversationId: conversation },
};
},
};
return Object.freeze(binder);
}
//# sourceMappingURL=verifiedThreads.js.map