@inixiative /图章
赠送王国徽章。
一、 印 是Kingdom使用集成的唯一授权。它列出了资源、操作、镜头和限制,并且可以撤销。它的受赠者是一个用户或一个集成,例如一个配对的Foundry或一台机器的本地Archive。被授权方向它提供一个访问令牌和一个由其设备密钥(RFC 9449)签名的DPoP证明。
这个包是该协议的一个实现,由Kingdom(验证)和Archive, Foundry和Oracle(呈现)共享:
contracts:连线模式:密钥、镜头、提议、配对请求、交付凭据、describe和execute,以及对话框架。proof:创建和验证DPoP证明(ES256, nonce-bound, access-token-bound)。files:用于密钥和凭据的私有0600 JSON文件。client:- 一个 安装 (本地铸造厂,档案馆或甲骨文)是一个演员知道王国的关键:
registerInstallation,然后requestRegistration询问它需要什么(它期望的所有者,通过组织id或编号,以及通过id或种类和名称的资源,以及它们的操作),并返回一个人在Kingdom中声明的评审代码(aregisterIntegration查询),其中审查以该所有者和所选资源打开collectSignet和saveCollectedSignet.installationInquiries,installationSignets,cancelInstallationInquiry,enrollInstallationSignet和rotateInstallationKey担任安装; pairInstallation整个配对(注册,请求,等待套接字,确认所有者,收集)和holdInstallationSignets为安装的集成所持有的每个Signet保留一个凭据文件,登记以后授予的凭据并删除已撤销的凭据;InstallationSocket王国对安装的实时连线:它验证密钥,接收安装在连接和每次更改时的查询和Signets的快照,保持安装的集成在线标记,宣传其查看器URL,并在套接字关闭时轮询相同的读取;- 一个 本人或其代理人 使用Kingdom API令牌加上其密钥的证明来充当自己:
requestSignet要求在集成(a)上签名signetRequest查询(在调用者管理集成时立即批准);awaitSignet民意调查collectSignet直到获得批准,并且enrollSignet在直接授予拥有人的印章上登记密钥(owner/grant)。saveCollectedSignet将结果写入键旁边; SignetClient,它更新其访问令牌并对每个调用进行签名:describe,execute,任务解决,以及Foundry用于推理的运行操作(resolveRun,delegateRun,renewRun,revokeRun),并进行订阅运行releaseSubscription和reportSubscriptionLimits.
- 一个 安装 (本地铸造厂,档案馆或甲骨文)是一个演员知道王国的关键:
import { holdInstallationSignets, InstallationSocket, pairInstallation, SignetClient } from '@inixiative/signet';
const paired = await pairInstallation({
url: kingdom, root: dataDir, kind: 'archive', name: 'Laptop Archive', sourceId,
terms: {
name: 'Laptop Archive', lifecycle: 'ongoing', expiresAt: null, maxRequests: null, maxConcurrent: 4,
owner: { ownerModel: 'Organization', organization: 'inixiative' },
resources: [{ resourceKind: 'archiveLibrary', operations: ['sessions.write'] }],
},
onReview: ({ review }) => console.log(`Approve in Kingdom: ${review}`),
confirmOwner: async ({ ownerName }) => confirm(`Pair with ${ownerName}?`),
});
new InstallationSocket({
url: kingdom,
keyFile: paired.keyFile,
onSnapshot: ({ signets }) => holdInstallationSignets(kingdom, paired.keyFile, paired.directory, signets),
}).start();
const signet = await SignetClient.fromFile(paired.credentialFile);
await signet.execute({ integrationId, operation: 'sessions.write', input: { resourceId, snapshot, previousDigest: null } });
一个人的代理,拥有在王国铸造的API令牌:
import { awaitSignet, enrollSignet, generateSignetKey, requestSignet, saveCollectedSignet, SignetClient, writePrivateJson } from '@inixiative/signet';
await writePrivateJson(keyFile, generateSignetKey());
const { requestId, reviewCode } = await requestSignet(kingdom, keyFile, apiToken, {
name: 'Research agent', integrationId, lifecycle: 'ongoing', expiresAt: null, maxRequests: null, maxConcurrent: 1,
resources: [{ resourceId, operations: ['documents.read'] }],
});
const collected = await awaitSignet(kingdom, keyFile, requestId); // or, for a granted Signet:
// const collected = await enrollSignet(kingdom, keyFile, apiToken, { signetId, expectedRevision, name: 'Research agent' });
await saveCollectedSignet(credentialFile, kingdom, keyFile, collected);
const signet = await SignetClient.fromFile(credentialFile);
await signet.describe();
申报操作
由Kingdom执行操作的集成一般在这里声明它们,每个资源类型一个模块: threads.ts 铸造厂的 threads 资源, archive.ts 查阅档案 archiveLibrary. 每个都声明它的操作枚举、显示名称、每个操作接受的输入、它的透镜模式和透镜的缩小。 declaredOperationSchema 和 operationInputSchemas 将它们连接起来(操作名称在各个契约中是唯一的), operationInputKeys(operation) 给出了 access/execute 此外还需要按键操作 resourceId 和 limit, operationInputFromAccess(operation, input) 挑选并解析这些。Kingdom的目录、它的输入检查和它的调度读取这些内容,因此首先在这里添加一个新操作。
- 存档 (
archiveLibrary):documents.read,documents.search,sessions.write,sessions.delete. 镜头是{ documentIds?, fields? }({}到达每个文档)和narrowsArchiveLens缩小它。archiveSourceOperations(sessions.write,sessions.delete)是一对本地档案,按照自己的会话行事:王国将它们绑定到它的sourceId,所以他们的补助金不带镜头。archiveLensRefusal(operation, lens)说明为什么拨款不能带有镜头(搜索需要每个文件都包含内容)。
代理对话
对话包含了主机Foundry的主线程(Kingdom) docs/AGENT-CONVERSATIONS.md、铸造 docs/reference/CONVERSATIONS.md). 成员是主机铸造厂的印章 threads 资源;Kingdom接收每个呼叫,并通过主机的安装套接字进行中继,不存储会话或消息。
- 镜头。
signetLensSchema是严格形状的结合,archiveLensSchema | threadsLensSchema,因为资源授权按id命名其资源,而没有类型。resourceLensSchema(kind)赋予一种模样;王国会核对每一笔拨款与它储存的种类。螺纹透镜是{ threads, view: 'own' | 'thread', delivery: 'note' | 'turn', outbound: 'review' | 'auto' },术语默认为最窄的值。threads选择器是否开启form: v1版本{ form: 'ids', ids }(1-100个线程id);withMember和tag都是以固定的Signets命名的,除非在发布版本中添加它们,否则不会在任何地方进行解析,因此新表单永远不会无声地扩大访问范围。narrowsSignetLens是批准他人请求的规则:id的子集,own<thread,note<turn,review<auto. - 连接请求 可以按类型命名资源:
requestSignet需要{ resourceKind: 'threads', operations, lens },王国在审查前解决它。 - 每读取。
installationInquiries,installationSignets、套接字快照和describe单独阅读每一篇文章。这个包无法读取的条目将被删除并列在其中dropped其余的都留着。在Signet中,资源被一个接一个地读取:带有该包无法读取的透镜的资源(来自新王国的选择器表单,不适合其资源类型的透镜)被丢弃,而Signet保留,因此安装永远不会丢失持有的Signet,也不会错误地将一个成员视为已撤销的资源。快照携带hostedSignets(本铸造厂成员的对话)和hostedSignetRequests(针对其集成的连接请求);持有的印章携带他们的resources. - 主人。
InstallationSocket需要threads,每个操作一个处理程序(thread.read,thread.prompt,thread.floor,prompt.resolve,thread.subscribe),回答threadResult(...)或者threadRefused(code). 具有未知选择器的帧被拒绝unknown_selector在任何处理程序运行之前。thread.subscribe回答与成员的观点和journalSeq它被拿走了,订阅从这里开始:appendThread(subscriptionId, entry)同时保存推送的条目,并且从不发送两次。每个追加都带有密集的订阅seq(过滤后的视图会跳过日记账,所以journalSeq不能透露损失);不能发送的条目仍然会花费它的seq,所以Kingdom看到了差距和成员的同步。订阅结束于thread.unsubscribe,当王国停止重申其租约(thread.lease;在最后一次扫描后90秒被丢弃,所以一次延迟的45秒扫描得以保留),或者当套接字丢弃时。 - 成员。 一个外部特工用
SignetSocket:它以其图章的表示形式进行验证(authenticateSignet,一个证明的束缚POST /api/v1/access/signetSocket与ath),在5分钟令牌到期前更新(renewPresentation),然后打开一个accessThread每个线程流:一个快照,然后追加,与王国的seq/resync规则。帧是按顺序处理的,每个流一个打开,王国的关闭带有原因:在修改后,流在新的镜头下重新打开,当主机离线时,它重新尝试后退,当呈现失效时,套接字重新呈现并重新打开,并在撤销或到期时结束(onClosed). 职位是分开的execute调用(thread.prompt),每个人都被录取并计分。持有会话符号的铸造厂在其安装套接字上打开相同的流(threadStreams,openThread)。
import { SignetClient, SignetSocket } from '@inixiative/signet';
const signet = await SignetClient.fromFile(credentialFile);
const socket = new SignetSocket({
client: signet,
onSnapshot: ({ threadId }, view) => show(threadId, view.entries),
onEntry: ({ threadId }, entry) => append(threadId, entry),
onClosed: ({ threadId }, reason) => console.log(`left ${threadId}: ${reason}`),
});
socket.open(threadId);
socket.start();
await signet.execute({
integrationId,
operation: 'thread.prompt',
input: { resourceId, threadId, postId: crypto.randomUUID(), text: 'The role you wanted opened' },
});
王国的OpenAPI规范(/openapi/docs)发布每个步骤的原始HTTP调用和凭据。
麻省理工学院