memeloop 0.0.1 → 0.1.0
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/README.md +63 -0
- package/dist/browser.cjs +1413 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +3066 -0
- package/dist/browser.d.ts +3066 -0
- package/dist/browser.js +43 -0
- package/dist/chunk-426CJUZP.js +630 -0
- package/dist/chunk-426CJUZP.js.map +1 -0
- package/dist/chunk-44YHBKDL.js +382 -0
- package/dist/chunk-44YHBKDL.js.map +1 -0
- package/dist/chunk-7ZDTB4VZ.js +63 -0
- package/dist/chunk-7ZDTB4VZ.js.map +1 -0
- package/dist/chunk-AZFYDWIN.js +98 -0
- package/dist/chunk-AZFYDWIN.js.map +1 -0
- package/dist/chunk-BGPU4RR7.js +367 -0
- package/dist/chunk-BGPU4RR7.js.map +1 -0
- package/dist/chunk-CCEFAOSH.js +496 -0
- package/dist/chunk-CCEFAOSH.js.map +1 -0
- package/dist/chunk-FWSY5HOA.js +63 -0
- package/dist/chunk-FWSY5HOA.js.map +1 -0
- package/dist/chunk-GYIOMQMY.js +8726 -0
- package/dist/chunk-GYIOMQMY.js.map +1 -0
- package/dist/chunk-HVB2BR3H.js +42 -0
- package/dist/chunk-HVB2BR3H.js.map +1 -0
- package/dist/chunk-K6P63KD4.js +68 -0
- package/dist/chunk-K6P63KD4.js.map +1 -0
- package/dist/chunk-MRKY4HGF.js +205 -0
- package/dist/chunk-MRKY4HGF.js.map +1 -0
- package/dist/chunk-QFHAAIIM.js +2657 -0
- package/dist/chunk-QFHAAIIM.js.map +1 -0
- package/dist/chunk-VZKQX5PP.js +1 -0
- package/dist/chunk-VZKQX5PP.js.map +1 -0
- package/dist/chunk-WAI6BODI.js +175 -0
- package/dist/chunk-WAI6BODI.js.map +1 -0
- package/dist/chunk-XHRBV6I3.js +3637 -0
- package/dist/chunk-XHRBV6I3.js.map +1 -0
- package/dist/chunk-YMNXDNDW.js +798 -0
- package/dist/chunk-YMNXDNDW.js.map +1 -0
- package/dist/conversation.cjs +208 -0
- package/dist/conversation.cjs.map +1 -0
- package/dist/conversation.d.cts +100 -0
- package/dist/conversation.d.ts +100 -0
- package/dist/conversation.js +21 -0
- package/dist/conversation.js.map +1 -0
- package/dist/device-network-portable.cjs +702 -0
- package/dist/device-network-portable.cjs.map +1 -0
- package/dist/device-network-portable.d.cts +110 -0
- package/dist/device-network-portable.d.ts +110 -0
- package/dist/device-network-portable.js +53 -0
- package/dist/device-network-portable.js.map +1 -0
- package/dist/device-network.cjs +906 -0
- package/dist/device-network.cjs.map +1 -0
- package/dist/device-network.d.cts +6 -0
- package/dist/device-network.d.ts +6 -0
- package/dist/device-network.js +59 -0
- package/dist/device-network.js.map +1 -0
- package/dist/fetchProvider-BpcGVSOG.d.cts +91 -0
- package/dist/fetchProvider-Cm0sO4Tl.d.ts +91 -0
- package/dist/index.cjs +27957 -5459
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +94 -1320
- package/dist/index.d.ts +94 -1320
- package/dist/index.js +10576 -2386
- package/dist/index.js.map +1 -1
- package/dist/interface-IrKBFtL1.d.cts +493 -0
- package/dist/interface-IrKBFtL1.d.ts +493 -0
- package/dist/llm-providers.cjs +43 -8
- package/dist/llm-providers.cjs.map +1 -1
- package/dist/llm-providers.d.cts +2 -1
- package/dist/llm-providers.d.ts +2 -1
- package/dist/llm-providers.js +4 -2
- package/dist/llm-providers.js.map +1 -1
- package/dist/loop-api.cjs +5177 -2050
- package/dist/loop-api.cjs.map +1 -1
- package/dist/loop-api.d.cts +11 -5
- package/dist/loop-api.d.ts +11 -5
- package/dist/loop-api.js +84 -49
- package/dist/mobile.cjs +2625 -0
- package/dist/mobile.cjs.map +1 -0
- package/dist/mobile.d.cts +6 -0
- package/dist/mobile.d.ts +6 -0
- package/dist/mobile.js +22 -0
- package/dist/mobile.js.map +1 -0
- package/dist/orchestration-portable-Bsf8YRfp.d.cts +2192 -0
- package/dist/orchestration-portable-Zw0g5tbj.d.ts +2192 -0
- package/dist/orchestration-portable.cjs +9553 -0
- package/dist/orchestration-portable.cjs.map +1 -0
- package/dist/orchestration-portable.d.cts +5 -0
- package/dist/orchestration-portable.d.ts +5 -0
- package/dist/orchestration-portable.js +290 -0
- package/dist/orchestration-portable.js.map +1 -0
- package/dist/pairingInvite-BXPWY3aM.d.cts +149 -0
- package/dist/pairingInvite-Cuz0wuq9.d.ts +149 -0
- package/dist/promptConcat-WTN-uHcz.d.cts +516 -0
- package/dist/promptConcat-deDSWZE3.d.ts +516 -0
- package/dist/providerRegistry-9trr5aoK.d.ts +86 -0
- package/dist/providerRegistry-xk_B1Ekv.d.cts +86 -0
- package/dist/registry-8eztoD_r.d.cts +393 -0
- package/dist/registry-DV24sI-3.d.ts +393 -0
- package/dist/remoteClient-B_spK019.d.ts +87 -0
- package/dist/remoteClient-CBggnRy3.d.cts +87 -0
- package/dist/runtime-SKSXVYIM.js +18 -0
- package/dist/runtime-SKSXVYIM.js.map +1 -0
- package/dist/scriptDeploymentPipeline-BAeo1dPb.d.cts +2463 -0
- package/dist/scriptDeploymentPipeline-DsnT0AG6.d.ts +2463 -0
- package/dist/syncCloudDevices-BEqwgrhD.d.ts +49 -0
- package/dist/syncCloudDevices-Ds_Kcgrv.d.cts +49 -0
- package/dist/types-7pYti-k9.d.cts +255 -0
- package/dist/types-CdFVSntj.d.ts +255 -0
- package/package.json +110 -35
- package/dist/anthropic.cjs +0 -72
- package/dist/anthropic.cjs.map +0 -1
- package/dist/anthropic.d.cts +0 -21
- package/dist/anthropic.d.ts +0 -21
- package/dist/anthropic.js +0 -21
- package/dist/anthropic.js.map +0 -1
- package/dist/azure.cjs +0 -72
- package/dist/azure.cjs.map +0 -1
- package/dist/azure.d.cts +0 -21
- package/dist/azure.d.ts +0 -21
- package/dist/azure.js +0 -21
- package/dist/azure.js.map +0 -1
- package/dist/chunk-3CN7DFBL.js +0 -4894
- package/dist/chunk-3CN7DFBL.js.map +0 -1
- package/dist/chunk-4AZ4D7U5.js +0 -32
- package/dist/chunk-4AZ4D7U5.js.map +0 -1
- package/dist/chunk-6ON4XSOV.js +0 -63
- package/dist/chunk-6ON4XSOV.js.map +0 -1
- package/dist/chunk-DJQNGIXX.js +0 -4793
- package/dist/chunk-DJQNGIXX.js.map +0 -1
- package/dist/chunk-FKQP6AOQ.js +0 -32
- package/dist/chunk-FKQP6AOQ.js.map +0 -1
- package/dist/chunk-OVJ7JJBA.js +0 -35
- package/dist/chunk-OVJ7JJBA.js.map +0 -1
- package/dist/chunk-P4UZ7IXC.js +0 -42
- package/dist/chunk-YHJ2AEFR.js +0 -4933
- package/dist/chunk-YHJ2AEFR.js.map +0 -1
- package/dist/chunk-YVK7RYRO.js +0 -4973
- package/dist/chunk-YVK7RYRO.js.map +0 -1
- package/dist/code-assistant.json +0 -114
- package/dist/cohere.cjs +0 -72
- package/dist/cohere.cjs.map +0 -1
- package/dist/cohere.d.cts +0 -21
- package/dist/cohere.d.ts +0 -21
- package/dist/cohere.js +0 -21
- package/dist/cohere.js.map +0 -1
- package/dist/deepseek.cjs +0 -72
- package/dist/deepseek.cjs.map +0 -1
- package/dist/deepseek.d.cts +0 -21
- package/dist/deepseek.d.ts +0 -21
- package/dist/deepseek.js +0 -21
- package/dist/deepseek.js.map +0 -1
- package/dist/dist-65U7OYRG.js +0 -1257
- package/dist/dist-65U7OYRG.js.map +0 -1
- package/dist/fetchProvider-Cu4WkU5O.d.cts +0 -819
- package/dist/fetchProvider-Cu4WkU5O.d.ts +0 -819
- package/dist/frontend-ui-ux.json +0 -105
- package/dist/general-assistant.json +0 -95
- package/dist/git-master.json +0 -51
- package/dist/google-vertex.cjs +0 -72
- package/dist/google-vertex.cjs.map +0 -1
- package/dist/google-vertex.d.cts +0 -21
- package/dist/google-vertex.d.ts +0 -21
- package/dist/google-vertex.js +0 -21
- package/dist/google-vertex.js.map +0 -1
- package/dist/google.cjs +0 -72
- package/dist/google.cjs.map +0 -1
- package/dist/google.d.cts +0 -21
- package/dist/google.d.ts +0 -21
- package/dist/google.js +0 -21
- package/dist/google.js.map +0 -1
- package/dist/groq.cjs +0 -72
- package/dist/groq.cjs.map +0 -1
- package/dist/groq.d.cts +0 -21
- package/dist/groq.d.ts +0 -21
- package/dist/groq.js +0 -21
- package/dist/groq.js.map +0 -1
- package/dist/index.d.mts +0 -3203
- package/dist/index.mjs +0 -7064
- package/dist/index.mjs.map +0 -1
- package/dist/mistral.cjs +0 -72
- package/dist/mistral.cjs.map +0 -1
- package/dist/mistral.d.cts +0 -21
- package/dist/mistral.d.ts +0 -21
- package/dist/mistral.js +0 -21
- package/dist/mistral.js.map +0 -1
- package/dist/multipart-parser-EJCXIUHC.js +0 -372
- package/dist/multipart-parser-EJCXIUHC.js.map +0 -1
- package/dist/openai.cjs +0 -72
- package/dist/openai.cjs.map +0 -1
- package/dist/openai.d.cts +0 -21
- package/dist/openai.d.ts +0 -21
- package/dist/openai.js +0 -21
- package/dist/openai.js.map +0 -1
- package/dist/perplexity.cjs +0 -72
- package/dist/perplexity.cjs.map +0 -1
- package/dist/perplexity.d.cts +0 -21
- package/dist/perplexity.d.ts +0 -21
- package/dist/perplexity.js +0 -21
- package/dist/perplexity.js.map +0 -1
- package/dist/playwright.json +0 -52
- package/dist/promptConcat-BJdazTg5.d.cts +0 -1832
- package/dist/promptConcat-BJdazTg5.d.ts +0 -1832
- package/dist/promptConcat-CAkpni_8.d.cts +0 -1834
- package/dist/promptConcat-CAkpni_8.d.ts +0 -1834
- package/dist/promptConcat-CfH5-GAE.d.cts +0 -1036
- package/dist/promptConcat-ChcAZOOL.d.ts +0 -1036
- package/dist/promptConcat-G5TnJVRy.d.cts +0 -1800
- package/dist/promptConcat-G5TnJVRy.d.ts +0 -1800
- package/dist/promptConcat-L72eowzp.d.ts +0 -1090
- package/dist/promptConcat-eLHdN7K8.d.cts +0 -1090
- package/dist/src-VTSXKG72.js +0 -1409
- package/dist/src-VTSXKG72.js.map +0 -1
- package/dist/togetherai.cjs +0 -72
- package/dist/togetherai.cjs.map +0 -1
- package/dist/togetherai.d.cts +0 -21
- package/dist/togetherai.d.ts +0 -21
- package/dist/togetherai.js +0 -21
- package/dist/togetherai.js.map +0 -1
- package/dist/types-B0Jm2l38.d.cts +0 -767
- package/dist/types-B0Jm2l38.d.ts +0 -767
- package/dist/xai.cjs +0 -72
- package/dist/xai.cjs.map +0 -1
- package/dist/xai.d.cts +0 -21
- package/dist/xai.d.ts +0 -21
- package/dist/xai.js +0 -21
- package/dist/xai.js.map +0 -1
- /package/dist/{chunk-P4UZ7IXC.js.map → browser.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sync/attachmentRpcCodec.ts","../src/sync/chatSyncEngine.ts","../src/sync/peerNodeAdapter.ts","../src/device-network/deviceOrchestrationTransport.ts","../src/device-network/libp2pSyncProtocol.ts","../src/device-network/libp2pDeviceSyncTransport.ts","../src/device-network/libp2pRpcProtocol.ts","../src/device-network/localTrustDeviceAuthorizer.ts","../src/device-network/pairingInvite.ts","../src/sync/protocol.ts"],"sourcesContent":["/**\n * 将节点 RPC `memeloop.storage.getAttachmentBlob` 的返回值解码为同步引擎可用的 BLOB。\n */\n\nexport function decodeAttachmentBlobRpc(\n result: unknown,\n): { data: Uint8Array; filename: string; mimeType: string; size: number } | null {\n if (result == null || typeof result !== 'object') return null;\n const r = result as {\n found?: boolean;\n error?: string;\n dataBase64?: string;\n filename?: string;\n mimeType?: string;\n size?: number;\n };\n if (r.error || !r.found || typeof r.dataBase64 !== 'string') return null;\n let data: Uint8Array;\n try {\n const binary = atob(r.dataBase64);\n if (!binary.length) return null;\n data = Uint8Array.from(binary, (character) => character.charCodeAt(0));\n } catch {\n return null;\n }\n return {\n data,\n filename: typeof r.filename === 'string' ? r.filename : 'attachment',\n mimeType: typeof r.mimeType === 'string' ? r.mimeType : 'application/octet-stream',\n size: typeof r.size === 'number' && r.size > 0 ? r.size : data.byteLength,\n };\n}\n","import type { AttachmentReference, ChatMessage } from '../conversation/index.js';\nimport type { ConversationMeta } from './protocol.js';\n\nimport type { IAgentStorage } from '../types.js';\n\nexport interface ChatSyncPeer {\n nodeId: string;\n /**\n * 取远端当前的 versionVector,并返回对方缺失的会话元数据。\n */\n exchangeVersionVector(localVersion: Record<string, number>): Promise<{\n remoteVersion: Record<string, number>;\n missingForRemote: ConversationMeta[];\n }>;\n\n /**\n * 将本地缺失的 metadata 从该 peer 拉回来。\n */\n pullMissingMetadata(sinceVersion: Record<string, number>): Promise<ConversationMeta[]>;\n\n /**\n * 按需拉取消息正文(TidGi / 审查单 Phase 4:消息级同步)。\n * 返回远端有而本地 unknownMessageIds 之外的新消息。\n */\n pullMissingMessages?(conversationId: string, knownMessageIds: string[]): Promise<ChatMessage[]>;\n\n /**\n * 按 contentHash 拉取附件二进制(与 `ChatMessage.attachments` / `AttachmentRef` 对齐)。\n * 典型实现:对 peer 发 `memeloop.storage.getAttachmentBlob` RPC。\n */\n pullAttachmentBlob?(\n contentHash: string,\n ): Promise<{ data: Uint8Array; filename: string; mimeType: string; size: number } | null>;\n}\n\nexport interface ChatSyncEngineOptions {\n nodeId: string;\n storage: IAgentStorage;\n peers: () => ChatSyncPeer[];\n}\n\nexport class ChatSyncEngine {\n private readonly nodeId: string;\n private readonly storage: IAgentStorage;\n private readonly getPeers: () => ChatSyncPeer[];\n private versionVector: Record<string, number> = {};\n\n constructor(options: ChatSyncEngineOptions) {\n this.nodeId = options.nodeId;\n this.storage = options.storage;\n this.getPeers = options.peers;\n this.versionVector[this.nodeId] = 0;\n }\n\n /**\n * 在本节点新产生一条消息时调用,增加本节点的 lamportClock。\n */\n public bumpLocalVersion(): void {\n this.versionVector[this.nodeId] = (this.versionVector[this.nodeId] ?? 0) + 1;\n }\n\n /**\n * 执行一次与所有 peer 的增量同步(metadata 级别),并尽力拉取缺失消息。\n */\n public async syncOnce(): Promise<void> {\n const peers = this.getPeers();\n if (peers.length === 0) return;\n\n const localVersion = { ...this.versionVector };\n const pulledConversations = new Set<string>();\n\n for (const peer of peers) {\n const { remoteVersion, missingForRemote } = await peer.exchangeVersionVector(localVersion);\n\n const missingForLocal = await peer.pullMissingMetadata(this.versionVector);\n\n for (const meta of missingForLocal) {\n await this.storage.upsertConversationMetadata(meta);\n pulledConversations.add(meta.conversationId);\n }\n\n for (const [nodeId, clock] of Object.entries(remoteVersion)) {\n const current = this.versionVector[nodeId] ?? 0;\n if (clock > current) {\n this.versionVector[nodeId] = clock;\n }\n }\n\n if (missingForRemote.length > 0) {\n this.bumpLocalVersion();\n }\n }\n\n for (const conversationId of pulledConversations) {\n await this.pullMessagesForConversationFromPeers(conversationId, peers);\n }\n }\n\n /**\n * Anti-entropy:先 syncOnce,再对已知会话逐个向各 peer 拉取缺失消息(参考审查单「定期对账」)。\n */\n public async antiEntropyOnce(): Promise<void> {\n await this.syncOnce();\n const list = await this.storage.listConversations({ limit: 500 });\n const peers = this.getPeers();\n for (const meta of list) {\n await this.pullMessagesForConversationFromPeers(meta.conversationId, peers);\n }\n }\n\n private async pullMessagesForConversationFromPeers(\n conversationId: string,\n peers: ChatSyncPeer[],\n ): Promise<void> {\n const localMsgs = await this.storage.getMessages(conversationId, { mode: 'full-content' });\n const knownIds = localMsgs.map((m) => m.messageId);\n\n for (const peer of peers) {\n if (!peer.pullMissingMessages) continue;\n try {\n const incoming = await peer.pullMissingMessages(conversationId, knownIds);\n if (incoming.length > 0) {\n await this.storage.insertMessagesIfAbsent(incoming);\n await this.ensureAttachmentsFromMessages(incoming, peers);\n }\n } catch {\n /* 单 peer 失败不阻塞 */\n }\n }\n }\n\n /** 从消息元数据收集 `attachments[].contentHash`,对本地缺失 BLOB 的哈希向各 peer 拉取并 `saveAttachment`。 */\n private async ensureAttachmentsFromMessages(\n messages: ChatMessage[],\n peers: ChatSyncPeer[],\n ): Promise<void> {\n const hashes = new Set<string>();\n for (const m of messages) {\n for (const a of m.attachments ?? []) {\n if (a.contentHash) hashes.add(a.contentHash);\n }\n }\n for (const h of hashes) {\n const reference = await this.storage.getAttachment(h);\n if (reference) {\n const reader = this.storage.readAttachmentData?.bind(this.storage);\n if (!reader) continue;\n const bytes = await reader(h);\n if (bytes && bytes.length > 0) continue;\n }\n\n for (const peer of peers) {\n const pull = peer.pullAttachmentBlob?.bind(peer);\n if (!pull) continue;\n try {\n const blob = await pull(h);\n if (blob?.data?.length) {\n const ar: AttachmentReference = {\n contentHash: h,\n filename: blob.filename,\n mimeType: blob.mimeType,\n size: blob.size > 0 ? blob.size : blob.data.length,\n };\n await this.storage.saveAttachment(ar, blob.data);\n break;\n }\n } catch {\n /* try next peer */\n }\n }\n }\n }\n\n public getVersionVector(): Record<string, number> {\n return { ...this.versionVector };\n }\n\n public getStorage(): IAgentStorage {\n return this.storage;\n }\n}\n","import type { ChatMessage } from '../conversation/index.js';\nimport type { ConversationMeta } from './protocol.js';\n\nimport type { ChatSyncPeer } from './chatSyncEngine.js';\n\nexport interface PeerNodeTransport {\n nodeId: string;\n exchangeVersionVector(\n targetNodeId: string,\n localVersion: Record<string, number>,\n ): Promise<{\n remoteVersion: Record<string, number>;\n missingForRemote: ConversationMeta[];\n }>;\n pullMissingMetadata(\n targetNodeId: string,\n sinceVersion: Record<string, number>,\n ): Promise<ConversationMeta[]>;\n pullMissingMessages?(\n targetNodeId: string,\n conversationId: string,\n knownMessageIds: string[],\n ): Promise<ChatMessage[]>;\n\n /** 从指定节点拉取附件 BLOB(如 `memeloop.storage.getAttachmentBlob`)。 */\n pullAttachmentBlob?(\n targetNodeId: string,\n contentHash: string,\n ): Promise<{ data: Uint8Array; filename: string; mimeType: string; size: number } | null>;\n}\n\nexport class PeerNodeSyncAdapter implements ChatSyncPeer {\n public readonly nodeId: string;\n private readonly transport: PeerNodeTransport;\n\n constructor(nodeId: string, transport: PeerNodeTransport) {\n this.nodeId = nodeId;\n this.transport = transport;\n }\n\n exchangeVersionVector(localVersion: Record<string, number>) {\n return this.transport.exchangeVersionVector(this.nodeId, localVersion);\n }\n\n pullMissingMetadata(sinceVersion: Record<string, number>) {\n return this.transport.pullMissingMetadata(this.nodeId, sinceVersion);\n }\n\n pullMissingMessages(conversationId: string, knownMessageIds: string[]): Promise<ChatMessage[]> {\n const function_ = this.transport.pullMissingMessages?.bind(this.transport);\n if (!function_) {\n return Promise.resolve([]);\n }\n return function_(this.nodeId, conversationId, knownMessageIds);\n }\n\n pullAttachmentBlob(contentHash: string) {\n const function_ = this.transport.pullAttachmentBlob?.bind(this.transport);\n if (!function_) {\n return Promise.resolve(null);\n }\n return function_(this.nodeId, contentHash);\n }\n}\n","import { OrchestrationError } from '../orchestration/errors.js';\nimport type { RemoteOrchestrationRequest, RemoteOrchestrationResponse, RemoteOrchestrationTransport, RemoteOrchestrationTransportOptions } from '../orchestration/remoteClient.js';\nimport type { DeviceConnectionGrant, DeviceNetworkService, MemeLoopDuplexStream } from './types.js';\n\nexport const DEVICE_ORCHESTRATION_PROTOCOL = '/memeloop/orchestration/1.0.0' as const;\nconst DEFAULT_MAX_FRAME_BYTES = 1024 * 1024;\n\nexport interface DeviceOrchestrationTransportOptions {\n deviceNetwork: Pick<DeviceNetworkService, 'openStream'>;\n peerId: string;\n grantProvider?: (\n peerId: string,\n ) => DeviceConnectionGrant | undefined | Promise<DeviceConnectionGrant | undefined>;\n maxFrameBytes?: number;\n}\n\nexport interface DeviceOrchestrationStreamHandlerInput {\n remotePeerId: string;\n stream: MemeLoopDuplexStream;\n authorize?: (presentedGrant: DeviceConnectionGrant | undefined) => boolean | Promise<boolean>;\n}\n\nexport type RemoteOrchestrationHandler = {\n request(request: RemoteOrchestrationRequest): Promise<RemoteOrchestrationResponse>;\n watch(\n request: RemoteOrchestrationRequest,\n options?: RemoteOrchestrationTransportOptions,\n ): AsyncIterable<RemoteOrchestrationResponse>;\n};\n\nexport interface DeviceOrchestrationStreamHandlerOptions {\n resolveHandler: (\n remotePeerId: string,\n ) => RemoteOrchestrationHandler | Promise<RemoteOrchestrationHandler>;\n maxFrameBytes?: number;\n}\n\nexport type DeviceOrchestrationStreamHandler = (\n input: DeviceOrchestrationStreamHandlerInput,\n) => Promise<void>;\n\ninterface DeviceOrchestrationRequestEnvelope {\n type: 'memeloop-device-orchestration-request-v1';\n request: RemoteOrchestrationRequest;\n grant?: DeviceConnectionGrant;\n}\n\nfunction orchestrationTransportError(\n code: 'CANCELLED' | 'EXHAUSTED' | 'INVALID' | 'UNAVAILABLE',\n message: string,\n): OrchestrationError {\n return new OrchestrationError({\n code,\n message,\n retryable: code === 'UNAVAILABLE',\n });\n}\n\nfunction assertFrameLimit(limit: number): void {\n if (!Number.isSafeInteger(limit) || limit < 256) {\n throw new TypeError('maxFrameBytes must be a safe integer of at least 256');\n }\n}\n\nasync function* encodeLines(\n values: AsyncIterable<unknown> | Iterable<unknown>,\n maxFrameBytes: number,\n): AsyncIterable<Uint8Array> {\n const encoder = new TextEncoder();\n for await (const value of values) {\n const frame = encoder.encode(`${JSON.stringify(value)}\\n`);\n if (frame.byteLength > maxFrameBytes) {\n throw orchestrationTransportError(\n 'EXHAUSTED',\n `device orchestration frame exceeds ${maxFrameBytes} bytes`,\n );\n }\n yield frame;\n }\n}\n\nasync function* decodeLines(\n source: AsyncIterable<Uint8Array>,\n maxFrameBytes: number,\n): AsyncIterable<unknown> {\n const decoder = new TextDecoder();\n let buffered = '';\n for await (const chunk of source) {\n buffered += decoder.decode(chunk, { stream: true });\n for (;;) {\n const newline = buffered.indexOf('\\n');\n if (newline < 0) break;\n const line = buffered.slice(0, newline);\n buffered = buffered.slice(newline + 1);\n if (!line) continue;\n if (new TextEncoder().encode(line).byteLength > maxFrameBytes) {\n throw orchestrationTransportError(\n 'EXHAUSTED',\n `device orchestration frame exceeds ${maxFrameBytes} bytes`,\n );\n }\n try {\n yield JSON.parse(line) as unknown;\n } catch {\n throw orchestrationTransportError(\n 'INVALID',\n 'device orchestration stream contains invalid JSON',\n );\n }\n }\n if (new TextEncoder().encode(buffered).byteLength > maxFrameBytes) {\n throw orchestrationTransportError(\n 'EXHAUSTED',\n `device orchestration frame exceeds ${maxFrameBytes} bytes`,\n );\n }\n }\n buffered += decoder.decode();\n if (buffered.trim()) {\n try {\n yield JSON.parse(buffered) as unknown;\n } catch {\n throw orchestrationTransportError(\n 'INVALID',\n 'device orchestration stream contains invalid trailing JSON',\n );\n }\n }\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw orchestrationTransportError('CANCELLED', 'device orchestration request was cancelled');\n }\n}\n\nasync function openAuthenticatedStream(options: DeviceOrchestrationTransportOptions): Promise<{\n stream: MemeLoopDuplexStream;\n grant: DeviceConnectionGrant | undefined;\n}> {\n const grant = await options.grantProvider?.(options.peerId);\n return {\n stream: await options.deviceNetwork.openStream(\n options.peerId,\n DEVICE_ORCHESTRATION_PROTOCOL,\n grant,\n ),\n grant,\n };\n}\n\nasync function writeRequest(\n stream: MemeLoopDuplexStream,\n request: RemoteOrchestrationRequest,\n grant: DeviceConnectionGrant | undefined,\n maxFrameBytes: number,\n): Promise<void> {\n const envelope: DeviceOrchestrationRequestEnvelope = {\n type: 'memeloop-device-orchestration-request-v1',\n request,\n ...(grant ? { grant } : {}),\n };\n await stream.sink(encodeLines([envelope], maxFrameBytes));\n}\n\n/**\n * Carry the portable resource protocol over an already authenticated and\n * encrypted device-network stream. No bearer credential crosses the link:\n * authorization is bound to the paired peer identity opening the protocol.\n */\nexport function createDeviceOrchestrationTransport(\n options: DeviceOrchestrationTransportOptions,\n): RemoteOrchestrationTransport {\n const maxFrameBytes = options.maxFrameBytes ?? DEFAULT_MAX_FRAME_BYTES;\n assertFrameLimit(maxFrameBytes);\n\n return {\n async request(request, transportOptions = {}) {\n throwIfAborted(transportOptions.signal);\n const { stream, grant } = await openAuthenticatedStream(options);\n const closeOnAbort = () => {\n void stream.close();\n };\n transportOptions.signal?.addEventListener('abort', closeOnAbort, {\n once: true,\n });\n try {\n await writeRequest(stream, request, grant, maxFrameBytes);\n let response: RemoteOrchestrationResponse | undefined;\n for await (const value of decodeLines(stream.source, maxFrameBytes)) {\n if (response) {\n throw orchestrationTransportError(\n 'INVALID',\n 'device orchestration request returned multiple responses',\n );\n }\n response = value as RemoteOrchestrationResponse;\n }\n throwIfAborted(transportOptions.signal);\n if (!response) {\n throw orchestrationTransportError(\n 'UNAVAILABLE',\n 'device orchestration request returned no response',\n );\n }\n return response;\n } finally {\n transportOptions.signal?.removeEventListener('abort', closeOnAbort);\n await stream.close().catch(() => undefined);\n }\n },\n async *watch(request, transportOptions = {}) {\n throwIfAborted(transportOptions.signal);\n const { stream, grant } = await openAuthenticatedStream(options);\n const closeOnAbort = () => {\n void stream.close();\n };\n transportOptions.signal?.addEventListener('abort', closeOnAbort, {\n once: true,\n });\n try {\n await writeRequest(stream, request, grant, maxFrameBytes);\n for await (const value of decodeLines(stream.source, maxFrameBytes)) {\n throwIfAborted(transportOptions.signal);\n yield value as RemoteOrchestrationResponse;\n }\n throwIfAborted(transportOptions.signal);\n } finally {\n transportOptions.signal?.removeEventListener('abort', closeOnAbort);\n await stream.close().catch(() => undefined);\n }\n },\n };\n}\n\nasync function readSingleRequest(\n stream: MemeLoopDuplexStream,\n maxFrameBytes: number,\n): Promise<DeviceOrchestrationRequestEnvelope> {\n let envelope: DeviceOrchestrationRequestEnvelope | undefined;\n for await (const value of decodeLines(stream.source, maxFrameBytes)) {\n if (envelope) {\n throw orchestrationTransportError(\n 'INVALID',\n 'device orchestration stream accepts exactly one request',\n );\n }\n if (\n value === null ||\n typeof value !== 'object' ||\n Array.isArray(value) ||\n (value as Record<string, unknown>).type !== 'memeloop-device-orchestration-request-v1' ||\n (value as Record<string, unknown>).request === null ||\n typeof (value as Record<string, unknown>).request !== 'object'\n ) {\n throw orchestrationTransportError(\n 'INVALID',\n 'device orchestration request envelope is invalid',\n );\n }\n envelope = value as DeviceOrchestrationRequestEnvelope;\n }\n if (!envelope) {\n throw orchestrationTransportError('INVALID', 'device orchestration request is missing');\n }\n return envelope;\n}\n\n/** Bind a trusted peer identity to a policy-scoped orchestration handler. */\nexport function createDeviceOrchestrationStreamHandler(\n options: DeviceOrchestrationStreamHandlerOptions,\n): DeviceOrchestrationStreamHandler {\n const maxFrameBytes = options.maxFrameBytes ?? DEFAULT_MAX_FRAME_BYTES;\n assertFrameLimit(maxFrameBytes);\n return async ({ remotePeerId, stream, authorize }) => {\n const abort = new AbortController();\n try {\n const envelope = await readSingleRequest(stream, maxFrameBytes);\n if (authorize && !(await authorize(envelope.grant))) {\n throw orchestrationTransportError('UNAVAILABLE', 'device_not_trusted');\n }\n const request = envelope.request;\n const handler = await options.resolveHandler(remotePeerId);\n if (request.operation === 'watch') {\n await stream.sink(\n encodeLines(handler.watch(request, { signal: abort.signal }), maxFrameBytes),\n );\n } else {\n await stream.sink(encodeLines([await handler.request(request)], maxFrameBytes));\n }\n } finally {\n abort.abort();\n await stream.close().catch(() => undefined);\n }\n };\n}\n","import type { DeviceConnectionGrant } from './types.js';\n\nexport const LIBP2P_SYNC_REQUEST_TYPE = 'memeloop-sync-request-v1';\nexport const LIBP2P_SYNC_RESPONSE_TYPE = 'memeloop-sync-response-v1';\n\nexport type Libp2pSyncMethod =\n | 'exchangeVersionVector'\n | 'pullMissingMetadata'\n | 'pullMissingMessages'\n | 'pullAttachmentBlob';\n\nexport interface Libp2pSyncRequest {\n type: typeof LIBP2P_SYNC_REQUEST_TYPE;\n id: string;\n method: Libp2pSyncMethod;\n params: unknown;\n grant?: DeviceConnectionGrant;\n}\n\nexport type Libp2pSyncResponse =\n | {\n type: typeof LIBP2P_SYNC_RESPONSE_TYPE;\n id: string;\n ok: true;\n result: unknown;\n }\n | {\n type: typeof LIBP2P_SYNC_RESPONSE_TYPE;\n id: string;\n ok: false;\n error: string;\n };\n\nexport interface AttachmentBlobWire {\n dataBase64Url: string;\n filename: string;\n mimeType: string;\n size: number;\n}\n\nconst syncMethods = new Set<Libp2pSyncMethod>([\n 'exchangeVersionVector',\n 'pullMissingMetadata',\n 'pullMissingMessages',\n 'pullAttachmentBlob',\n]);\n\nexport function isLibp2pSyncRequest(value: unknown): value is Libp2pSyncRequest {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return false;\n const record = value as Record<string, unknown>;\n return (\n record.type === LIBP2P_SYNC_REQUEST_TYPE &&\n typeof record.id === 'string' &&\n typeof record.method === 'string' &&\n syncMethods.has(record.method as Libp2pSyncMethod)\n );\n}\n\nexport function isLibp2pSyncResponse(value: unknown): value is Libp2pSyncResponse {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return false;\n const record = value as Record<string, unknown>;\n if (record.type !== LIBP2P_SYNC_RESPONSE_TYPE || typeof record.id !== 'string' || typeof record.ok !== 'boolean') return false;\n if (record.ok) return 'result' in record;\n return typeof record.error === 'string';\n}\n\nfunction isAttachmentBlobWire(value: unknown): value is AttachmentBlobWire {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return false;\n const record = value as Record<string, unknown>;\n return (\n typeof record.dataBase64Url === 'string' &&\n typeof record.filename === 'string' &&\n typeof record.mimeType === 'string' &&\n typeof record.size === 'number'\n );\n}\n\nexport async function attachmentBlobFromWire(value: unknown): Promise<\n {\n data: Uint8Array;\n filename: string;\n mimeType: string;\n size: number;\n } | null\n> {\n if (value === null) return null;\n if (!isAttachmentBlobWire(value)) throw new Error('invalid_sync_response');\n let data: Uint8Array;\n try {\n const base64 = value.dataBase64Url.replace(/-/g, '+').replace(/_/g, '/');\n const paddedBase64 = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');\n const binary = atob(paddedBase64);\n data = Uint8Array.from(binary, (character) => character.charCodeAt(0));\n } catch {\n throw new Error('invalid_sync_response');\n }\n return {\n data,\n filename: value.filename,\n mimeType: value.mimeType,\n size: value.size,\n };\n}\n","import type { ChatMessage } from '../conversation/index.js';\nimport type { ConversationMeta, VersionVector } from '../sync/protocol.js';\nimport { attachmentBlobFromWire, isLibp2pSyncResponse, LIBP2P_SYNC_REQUEST_TYPE, type Libp2pSyncMethod, type Libp2pSyncRequest } from './libp2pSyncProtocol.js';\nimport type { AttachmentBlob, Device, DeviceConnectionGrant, DeviceNetworkService, DeviceSyncTransport, ExchangeVersionVectorResult, MemeLoopDuplexStream } from './types.js';\n\nexport interface Libp2pDeviceSyncTransportOptions {\n nodeId: string;\n deviceNetwork: Pick<DeviceNetworkService, 'listDevices' | 'openStream'>;\n grantProvider?: (peerId: string) => Promise<DeviceConnectionGrant | undefined>;\n}\n\nexport class Libp2pDeviceSyncTransport implements DeviceSyncTransport {\n public readonly nodeId: string;\n private readonly deviceNetwork: Pick<DeviceNetworkService, 'listDevices' | 'openStream'>;\n private readonly grantProvider?: (peerId: string) => Promise<DeviceConnectionGrant | undefined>;\n\n constructor(options: Libp2pDeviceSyncTransportOptions) {\n this.nodeId = options.nodeId;\n this.deviceNetwork = options.deviceNetwork;\n this.grantProvider = options.grantProvider;\n }\n\n public listPeers(): Promise<Device[]> {\n return this.deviceNetwork.listDevices();\n }\n\n public exchangeVersionVector(peerId: string, localVersion: VersionVector): Promise<ExchangeVersionVectorResult> {\n return this.request(peerId, 'exchangeVersionVector', { localVersion }) as Promise<ExchangeVersionVectorResult>;\n }\n\n public pullMissingMetadata(peerId: string, sinceVersion: VersionVector): Promise<ConversationMeta[]> {\n return this.request(peerId, 'pullMissingMetadata', { sinceVersion }) as Promise<ConversationMeta[]>;\n }\n\n public pullMissingMessages(peerId: string, conversationId: string, knownMessageIds: string[]): Promise<ChatMessage[]> {\n return this.request(peerId, 'pullMissingMessages', { conversationId, knownMessageIds }) as Promise<ChatMessage[]>;\n }\n\n public async pullAttachmentBlob(peerId: string, contentHash: string): Promise<AttachmentBlob | null> {\n const result = await this.request(peerId, 'pullAttachmentBlob', { contentHash });\n return attachmentBlobFromWire(result);\n }\n\n private async request(peerId: string, method: Libp2pSyncMethod, parameters: unknown): Promise<unknown> {\n const grant = await this.grantProvider?.(peerId);\n const stream = await this.deviceNetwork.openStream(peerId, '/memeloop/sync/1.0.0', grant);\n const request: Libp2pSyncRequest = {\n type: LIBP2P_SYNC_REQUEST_TYPE,\n id: crypto.randomUUID(),\n method,\n params: parameters,\n grant,\n };\n await writeJsonToStream(stream, request);\n const response = await readJsonFromStream(stream);\n await stream.close();\n if (!isLibp2pSyncResponse(response)) throw new Error('invalid_sync_response');\n if (response.id !== request.id) throw new Error('sync_response_id_mismatch');\n if (!response.ok) throw new Error(response.error);\n return response.result;\n }\n}\n\nasync function writeJsonToStream(stream: MemeLoopDuplexStream, message: unknown): Promise<void> {\n const payload = new TextEncoder().encode(JSON.stringify(message));\n await stream.sink(async function*() {\n yield payload;\n }());\n}\n\nasync function readJsonFromStream(stream: MemeLoopDuplexStream): Promise<unknown> {\n const reader = stream.source[Symbol.asyncIterator]();\n const result = await reader.next();\n if (result.done || !result.value) throw new Error('sync_response_missing');\n return JSON.parse(new TextDecoder().decode(result.value)) as unknown;\n}\n","import type { DeviceConnectionGrant } from './types.js';\n\nexport const LIBP2P_RPC_REQUEST_TYPE = 'memeloop-rpc-request-v1';\nexport const LIBP2P_RPC_RESPONSE_TYPE = 'memeloop-rpc-response-v1';\n\nexport interface Libp2pRpcRequest {\n type: typeof LIBP2P_RPC_REQUEST_TYPE;\n id: string;\n method: string;\n params: unknown;\n grant?: DeviceConnectionGrant;\n}\n\nexport type Libp2pRpcResponse =\n | {\n type: typeof LIBP2P_RPC_RESPONSE_TYPE;\n id: string;\n ok: true;\n result: unknown;\n }\n | {\n type: typeof LIBP2P_RPC_RESPONSE_TYPE;\n id: string;\n ok: false;\n error: string;\n };\n\nexport function isLibp2pRpcRequest(value: unknown): value is Libp2pRpcRequest {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return false;\n const record = value as Record<string, unknown>;\n return (\n record.type === LIBP2P_RPC_REQUEST_TYPE &&\n typeof record.id === 'string' &&\n typeof record.method === 'string'\n );\n}\n\nexport function isLibp2pRpcResponse(value: unknown): value is Libp2pRpcResponse {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return false;\n const record = value as Record<string, unknown>;\n if (record.type !== LIBP2P_RPC_RESPONSE_TYPE || typeof record.id !== 'string' || typeof record.ok !== 'boolean') return false;\n if (record.ok) return 'result' in record;\n return typeof record.error === 'string';\n}\n","import type { DeviceAuthorizer, MemeLoopProtocol, TrustedDeviceRecord } from './types.js';\n\nexport interface LocalTrustDeviceAuthorizerOptions {\n trustedDevices?: Iterable<TrustedDeviceRecord>;\n getTrustedDevice?: (peerId: string) => TrustedDeviceRecord | undefined;\n allowPairingProtocol?: boolean;\n}\n\nconst PAIRING_PROTOCOL: MemeLoopProtocol = '/memeloop/pairing/1.0.0';\n\nexport class LocalTrustDeviceAuthorizer implements DeviceAuthorizer {\n private readonly trustedDevices = new Map<string, TrustedDeviceRecord>();\n private readonly allowPairingProtocol: boolean;\n\n constructor(private readonly options: LocalTrustDeviceAuthorizerOptions = {}) {\n this.allowPairingProtocol = options.allowPairingProtocol ?? true;\n for (const record of options.trustedDevices ?? []) {\n this.trustedDevices.set(record.peerId, record);\n }\n }\n\n public setTrustedDevice(record: TrustedDeviceRecord): void {\n this.trustedDevices.set(record.peerId, record);\n }\n\n public removeTrustedDevice(peerId: string): void {\n this.trustedDevices.delete(peerId);\n }\n\n public async canOpenProtocol(input: {\n remotePeerId: string;\n protocol: MemeLoopProtocol;\n }): Promise<boolean> {\n const record = this.options.getTrustedDevice?.(input.remotePeerId) ?? this.trustedDevices.get(input.remotePeerId);\n if (record?.revokedAt) return false;\n if (input.protocol === PAIRING_PROTOCOL) return this.allowPairingProtocol;\n return record !== undefined;\n }\n}\n","import type { Device } from './types.js';\n\nexport const DEVICE_PAIRING_INVITE_PROTOCOL = 'memeloop-device-pairing-v1';\nexport const DEVICE_PAIRING_INVITE_TTL_MS = 5 * 60_000;\nconst MAX_INVITE_LENGTH = 16 * 1024;\nconst MAX_ADDRESSES = 8;\n\nexport interface DevicePairingInvite {\n protocol: typeof DEVICE_PAIRING_INVITE_PROTOCOL;\n peerId: string;\n deviceName: string;\n multiaddrs: string[];\n createdAt: number;\n expiresAt: number;\n}\n\nfunction requireText(value: string, name: string, maxLength: number): string {\n const trimmed = value.trim();\n if (!trimmed || trimmed.length > maxLength) {\n throw new Error(`invalid device pairing invite ${name}`);\n }\n return trimmed;\n}\n\nfunction validateAddresses(addresses: readonly string[]): string[] {\n const unique = [...new Set(addresses.map((address) => address.trim()))]\n .filter(Boolean);\n if (\n unique.length === 0 ||\n unique.length > MAX_ADDRESSES ||\n unique.some((address) =>\n address.length > 2048 ||\n !address.startsWith('/') ||\n (!address.includes('/ws') && !address.includes('/wss'))\n )\n ) {\n throw new Error('device pairing invite requires WebSocket multiaddrs');\n }\n return unique;\n}\n\nexport function createDevicePairingInvite(\n device: Pick<Device, 'peerId' | 'displayName' | 'multiaddrs'>,\n options: { now?: number; ttlMs?: number } = {},\n): DevicePairingInvite {\n const createdAt = options.now ?? Date.now();\n const ttlMs = options.ttlMs ?? DEVICE_PAIRING_INVITE_TTL_MS;\n if (!Number.isSafeInteger(createdAt) || !Number.isSafeInteger(ttlMs) || ttlMs <= 0 || ttlMs > DEVICE_PAIRING_INVITE_TTL_MS) {\n throw new Error('invalid device pairing invite lifetime');\n }\n return {\n protocol: DEVICE_PAIRING_INVITE_PROTOCOL,\n peerId: requireText(device.peerId, 'peerId', 256),\n deviceName: requireText(device.displayName, 'deviceName', 256),\n multiaddrs: validateAddresses(device.multiaddrs ?? []),\n createdAt,\n expiresAt: createdAt + ttlMs,\n };\n}\n\nexport function encodeDevicePairingInvite(invite: DevicePairingInvite): string {\n const validated = parseDevicePairingInvite(JSON.stringify(invite), {\n now: invite.createdAt,\n });\n return JSON.stringify(validated);\n}\n\nexport function parseDevicePairingInvite(\n serialized: string,\n options: { now?: number } = {},\n): DevicePairingInvite {\n if (!serialized || serialized.length > MAX_INVITE_LENGTH) {\n throw new Error('invalid device pairing invite length');\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(serialized);\n } catch {\n throw new Error('device pairing invite is not valid JSON');\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('invalid device pairing invite');\n }\n const record = parsed as Record<string, unknown>;\n if (\n record.protocol !== DEVICE_PAIRING_INVITE_PROTOCOL ||\n typeof record.peerId !== 'string' ||\n typeof record.deviceName !== 'string' ||\n !Array.isArray(record.multiaddrs) ||\n record.multiaddrs.some((address) => typeof address !== 'string') ||\n typeof record.createdAt !== 'number' ||\n typeof record.expiresAt !== 'number' ||\n !Number.isSafeInteger(record.createdAt) ||\n !Number.isSafeInteger(record.expiresAt) ||\n record.expiresAt <= record.createdAt ||\n record.expiresAt - record.createdAt > DEVICE_PAIRING_INVITE_TTL_MS\n ) {\n throw new Error('invalid device pairing invite');\n }\n if (record.expiresAt <= (options.now ?? Date.now())) {\n throw new Error('device pairing invite has expired');\n }\n return {\n protocol: DEVICE_PAIRING_INVITE_PROTOCOL,\n peerId: requireText(record.peerId, 'peerId', 256),\n deviceName: requireText(record.deviceName, 'deviceName', 256),\n multiaddrs: validateAddresses(record.multiaddrs as string[]),\n createdAt: record.createdAt,\n expiresAt: record.expiresAt,\n };\n}\n","export type VersionVector = Record<string, number>;\n\nexport interface ConversationMeta {\n conversationId: string;\n title: string;\n lastMessagePreview: string;\n lastMessageTimestamp: number;\n messageCount: number;\n originNodeId: string;\n definitionId: string;\n instanceDelta?: Record<string, unknown>;\n isUserInitiated: boolean;\n sourceChannel?: {\n channelId: string;\n platform: string;\n imUserId: string;\n };\n}\n\nexport function isConversationMeta(value: unknown): value is ConversationMeta {\n if (value === null || typeof value !== 'object') return false;\n const o = value as Record<string, unknown>;\n return (\n typeof o.conversationId === 'string' &&\n typeof o.title === 'string' &&\n typeof o.originNodeId === 'string' &&\n typeof o.definitionId === 'string' &&\n typeof o.messageCount === 'number' &&\n typeof o.lastMessageTimestamp === 'number' &&\n typeof o.isUserInitiated === 'boolean'\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import {
|
|
2
|
+
registerToolParameterSchema
|
|
3
|
+
} from "./chunk-XHRBV6I3.js";
|
|
4
|
+
import {
|
|
5
|
+
registerHook
|
|
6
|
+
} from "./chunk-QFHAAIIM.js";
|
|
7
|
+
|
|
8
|
+
// src/permission/storage.ts
|
|
9
|
+
var TABLE_NAME = "permissions";
|
|
10
|
+
var STORAGE_KEY = "user";
|
|
11
|
+
function loadUserPermissions(database) {
|
|
12
|
+
try {
|
|
13
|
+
const row = database.prepare(`SELECT rulesJson FROM ${TABLE_NAME} WHERE source = ? LIMIT 1`).get(STORAGE_KEY);
|
|
14
|
+
if (row?.rulesJson) {
|
|
15
|
+
return JSON.parse(row.rulesJson);
|
|
16
|
+
}
|
|
17
|
+
} catch {
|
|
18
|
+
}
|
|
19
|
+
return { rules: [], source: "user" };
|
|
20
|
+
}
|
|
21
|
+
function saveUserPermissions(database, set) {
|
|
22
|
+
database.prepare(
|
|
23
|
+
`INSERT OR REPLACE INTO ${TABLE_NAME} (source, rulesJson, updatedAt)
|
|
24
|
+
VALUES (?, ?, ?)`
|
|
25
|
+
).run(set.source, JSON.stringify(set), Date.now());
|
|
26
|
+
}
|
|
27
|
+
var PERMISSIONS_TABLE_DDL = `
|
|
28
|
+
CREATE TABLE IF NOT EXISTS ${TABLE_NAME} (
|
|
29
|
+
source TEXT PRIMARY KEY,
|
|
30
|
+
rulesJson TEXT NOT NULL,
|
|
31
|
+
updatedAt INTEGER NOT NULL
|
|
32
|
+
);
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
// src/loopAPI/tokenTracker.ts
|
|
36
|
+
var TokenTracker = class {
|
|
37
|
+
promptTokens = 0;
|
|
38
|
+
completionTokens = 0;
|
|
39
|
+
contextWindow;
|
|
40
|
+
compactionThreshold;
|
|
41
|
+
outputBuffer;
|
|
42
|
+
compacting = false;
|
|
43
|
+
consecutiveCompactionFailures = 0;
|
|
44
|
+
maxConsecutiveFailures = 3;
|
|
45
|
+
constructor(config) {
|
|
46
|
+
this.contextWindow = config?.contextWindow ?? 2e5;
|
|
47
|
+
this.compactionThreshold = config?.compactionThreshold ?? 0.9;
|
|
48
|
+
this.outputBuffer = config?.outputBuffer ?? 16e3;
|
|
49
|
+
}
|
|
50
|
+
/** Record token usage from an LLM response */
|
|
51
|
+
recordUsage(promptTokens, completionTokens) {
|
|
52
|
+
this.promptTokens += promptTokens;
|
|
53
|
+
this.completionTokens += completionTokens;
|
|
54
|
+
}
|
|
55
|
+
/** Manually set the prompt token count (e.g., from estimation) */
|
|
56
|
+
setPromptTokens(tokens) {
|
|
57
|
+
this.promptTokens = tokens;
|
|
58
|
+
}
|
|
59
|
+
/** Get current usage */
|
|
60
|
+
getUsage() {
|
|
61
|
+
const total = this.promptTokens + this.completionTokens;
|
|
62
|
+
const effectiveWindow = this.contextWindow - this.outputBuffer;
|
|
63
|
+
const usagePercent = total / effectiveWindow;
|
|
64
|
+
return {
|
|
65
|
+
promptTokens: this.promptTokens,
|
|
66
|
+
completionTokens: this.completionTokens,
|
|
67
|
+
totalTokens: total,
|
|
68
|
+
contextWindow: this.contextWindow,
|
|
69
|
+
usagePercent: Math.min(usagePercent, 1),
|
|
70
|
+
shouldCompact: usagePercent >= this.compactionThreshold && !this.compacting
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Check if auto-compaction should be triggered */
|
|
74
|
+
shouldTriggerCompaction() {
|
|
75
|
+
if (this.consecutiveCompactionFailures >= this.maxConsecutiveFailures) return false;
|
|
76
|
+
return this.getUsage().shouldCompact;
|
|
77
|
+
}
|
|
78
|
+
/** Mark that compaction is starting */
|
|
79
|
+
markCompactionStart() {
|
|
80
|
+
this.compacting = true;
|
|
81
|
+
}
|
|
82
|
+
/** Mark that compaction succeeded — reset token counts */
|
|
83
|
+
markCompactionSuccess(estimatedPostTokens) {
|
|
84
|
+
this.compacting = false;
|
|
85
|
+
this.promptTokens = estimatedPostTokens;
|
|
86
|
+
this.completionTokens = 0;
|
|
87
|
+
this.consecutiveCompactionFailures = 0;
|
|
88
|
+
}
|
|
89
|
+
/** Mark that compaction failed */
|
|
90
|
+
markCompactionFailure() {
|
|
91
|
+
this.compacting = false;
|
|
92
|
+
this.consecutiveCompactionFailures++;
|
|
93
|
+
}
|
|
94
|
+
/** Reset all counters */
|
|
95
|
+
reset() {
|
|
96
|
+
this.promptTokens = 0;
|
|
97
|
+
this.completionTokens = 0;
|
|
98
|
+
this.compacting = false;
|
|
99
|
+
this.consecutiveCompactionFailures = 0;
|
|
100
|
+
}
|
|
101
|
+
/** Get a human-readable summary */
|
|
102
|
+
formatUsage() {
|
|
103
|
+
const usage = this.getUsage();
|
|
104
|
+
const promptK = (usage.promptTokens / 1e3).toFixed(1);
|
|
105
|
+
const windowK = (usage.contextWindow / 1e3).toFixed(0);
|
|
106
|
+
const pct = (usage.usagePercent * 100).toFixed(1);
|
|
107
|
+
return `${promptK}K/${windowK}K tokens (${pct}%)`;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// src/llm/providerRegistry.ts
|
|
112
|
+
var ProviderRegistry = class {
|
|
113
|
+
providers = /* @__PURE__ */ new Map();
|
|
114
|
+
register(provider, config) {
|
|
115
|
+
this.providers.set(provider.name, {
|
|
116
|
+
provider,
|
|
117
|
+
config: {
|
|
118
|
+
name: provider.name,
|
|
119
|
+
baseUrl: config?.baseUrl,
|
|
120
|
+
apiKey: config?.apiKey
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
unregister(name) {
|
|
125
|
+
this.providers.delete(name);
|
|
126
|
+
}
|
|
127
|
+
get(name) {
|
|
128
|
+
return this.providers.get(name)?.provider;
|
|
129
|
+
}
|
|
130
|
+
getConfig(name) {
|
|
131
|
+
return this.providers.get(name)?.config;
|
|
132
|
+
}
|
|
133
|
+
upsertConfig(config) {
|
|
134
|
+
const existing = this.providers.get(config.name);
|
|
135
|
+
if (!existing) {
|
|
136
|
+
throw new Error(`Provider not found: ${config.name}`);
|
|
137
|
+
}
|
|
138
|
+
this.providers.set(config.name, {
|
|
139
|
+
provider: existing.provider,
|
|
140
|
+
config: {
|
|
141
|
+
name: config.name,
|
|
142
|
+
baseUrl: config.baseUrl,
|
|
143
|
+
apiKey: config.apiKey
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
list() {
|
|
148
|
+
return Array.from(this.providers.keys()).sort();
|
|
149
|
+
}
|
|
150
|
+
listConfigs() {
|
|
151
|
+
return this.list().map((name) => {
|
|
152
|
+
const config = this.providers.get(name)?.config;
|
|
153
|
+
if (!config) {
|
|
154
|
+
throw new Error(`Provider config missing: ${name}`);
|
|
155
|
+
}
|
|
156
|
+
return { ...config };
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
resolve(modelId) {
|
|
160
|
+
const [providerName, ...rest] = modelId.split("/");
|
|
161
|
+
const registered = this.providers.get(providerName);
|
|
162
|
+
if (!registered) {
|
|
163
|
+
throw new Error(`Provider not found: ${providerName}`);
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
provider: registered.provider,
|
|
167
|
+
providerName,
|
|
168
|
+
modelName: rest.length > 0 ? rest.join("/") : void 0
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// src/plugin/loader.ts
|
|
174
|
+
var loadedPlugins = /* @__PURE__ */ new Map();
|
|
175
|
+
var hookTypes = /* @__PURE__ */ new Set([
|
|
176
|
+
"PreToolUse",
|
|
177
|
+
"PostToolUse",
|
|
178
|
+
"UserPromptSubmit",
|
|
179
|
+
"ContextCompaction",
|
|
180
|
+
"AgentStart",
|
|
181
|
+
"AgentStop"
|
|
182
|
+
]);
|
|
183
|
+
function isHookType(value) {
|
|
184
|
+
return typeof value === "string" && hookTypes.has(value);
|
|
185
|
+
}
|
|
186
|
+
function validatePluginManifest(object) {
|
|
187
|
+
if (!object || typeof object !== "object") return null;
|
|
188
|
+
const manifest = object;
|
|
189
|
+
if (typeof manifest.name !== "string" || manifest.name.trim().length === 0 || typeof manifest.version !== "string" || manifest.version.trim().length === 0) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
name: manifest.name.trim(),
|
|
194
|
+
version: manifest.version.trim(),
|
|
195
|
+
description: typeof manifest.description === "string" ? manifest.description : "",
|
|
196
|
+
exports: validateExports(manifest.exports),
|
|
197
|
+
author: typeof manifest.author === "string" ? manifest.author : void 0,
|
|
198
|
+
minMemeloopVersion: typeof manifest.minMemeloopVersion === "string" ? manifest.minMemeloopVersion : void 0
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function validateExports(object) {
|
|
202
|
+
if (!object || typeof object !== "object") return void 0;
|
|
203
|
+
const exportsRecord = object;
|
|
204
|
+
return {
|
|
205
|
+
tools: Array.isArray(exportsRecord.tools) ? exportsRecord.tools.filter((tool) => typeof tool === "string") : void 0,
|
|
206
|
+
hooks: Array.isArray(exportsRecord.hooks) ? exportsRecord.hooks.filter(isHookType) : void 0
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
async function loadPluginModule(options) {
|
|
210
|
+
const { manifest, module, api, source = "" } = options;
|
|
211
|
+
const validManifest = validatePluginManifest(manifest);
|
|
212
|
+
if (!validManifest) return null;
|
|
213
|
+
if (loadedPlugins.has(validManifest.name)) {
|
|
214
|
+
return loadedPlugins.get(validManifest.name) ?? null;
|
|
215
|
+
}
|
|
216
|
+
if (!module || typeof module.activate !== "function") {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const cleanup = await module.activate(api);
|
|
220
|
+
const loaded = {
|
|
221
|
+
manifest: validManifest,
|
|
222
|
+
source,
|
|
223
|
+
module,
|
|
224
|
+
cleanup: typeof cleanup === "function" ? cleanup : void 0,
|
|
225
|
+
loadedAt: /* @__PURE__ */ new Date()
|
|
226
|
+
};
|
|
227
|
+
loadedPlugins.set(validManifest.name, loaded);
|
|
228
|
+
return loaded;
|
|
229
|
+
}
|
|
230
|
+
async function loadPluginModules(plugins) {
|
|
231
|
+
const loaded = [];
|
|
232
|
+
for (const plugin of plugins) {
|
|
233
|
+
const result = await loadPluginModule(plugin);
|
|
234
|
+
if (result) loaded.push(result);
|
|
235
|
+
}
|
|
236
|
+
return loaded;
|
|
237
|
+
}
|
|
238
|
+
function unloadPlugin(name) {
|
|
239
|
+
const loaded = loadedPlugins.get(name);
|
|
240
|
+
if (!loaded) return false;
|
|
241
|
+
try {
|
|
242
|
+
loaded.cleanup?.();
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.warn(`[plugin] Error during cleanup of "${name}":`, error);
|
|
245
|
+
}
|
|
246
|
+
loadedPlugins.delete(name);
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
function listPlugins() {
|
|
250
|
+
return Array.from(loadedPlugins.values());
|
|
251
|
+
}
|
|
252
|
+
function getLoadedPlugin(name) {
|
|
253
|
+
return loadedPlugins.get(name);
|
|
254
|
+
}
|
|
255
|
+
function isPluginLoaded(name) {
|
|
256
|
+
return loadedPlugins.has(name);
|
|
257
|
+
}
|
|
258
|
+
function unloadAllPlugins() {
|
|
259
|
+
for (const name of loadedPlugins.keys()) {
|
|
260
|
+
unloadPlugin(name);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/plugin/registry.ts
|
|
265
|
+
var PluginRegistryManager = class {
|
|
266
|
+
pluginRegistrations = /* @__PURE__ */ new Map();
|
|
267
|
+
ensureRegistration(pluginName) {
|
|
268
|
+
const existing = this.pluginRegistrations.get(pluginName);
|
|
269
|
+
if (existing) return existing;
|
|
270
|
+
const reg = {
|
|
271
|
+
pluginName,
|
|
272
|
+
tools: [],
|
|
273
|
+
hooks: []
|
|
274
|
+
};
|
|
275
|
+
this.pluginRegistrations.set(pluginName, reg);
|
|
276
|
+
return reg;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Create a PluginAPI instance that plugins use to register their capabilities.
|
|
280
|
+
*/
|
|
281
|
+
createPluginAPI(options = {}) {
|
|
282
|
+
const toolRegistry = options.toolRegistry;
|
|
283
|
+
const logger = options.logger ?? {
|
|
284
|
+
debug: (...arguments_) => {
|
|
285
|
+
console.debug("[plugin]", ...arguments_);
|
|
286
|
+
},
|
|
287
|
+
info: (...arguments_) => {
|
|
288
|
+
console.info("[plugin]", ...arguments_);
|
|
289
|
+
},
|
|
290
|
+
warn: (...arguments_) => {
|
|
291
|
+
console.warn("[plugin]", ...arguments_);
|
|
292
|
+
},
|
|
293
|
+
error: (...arguments_) => {
|
|
294
|
+
console.error("[plugin]", ...arguments_);
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
return {
|
|
298
|
+
logger,
|
|
299
|
+
registerTool(toolId, impl, schema, effect) {
|
|
300
|
+
if (effect === void 0) {
|
|
301
|
+
toolRegistry?.registerTool(toolId, impl, schema);
|
|
302
|
+
} else {
|
|
303
|
+
toolRegistry?.registerTool(toolId, impl, schema, effect);
|
|
304
|
+
}
|
|
305
|
+
if (schema) {
|
|
306
|
+
registerToolParameterSchema(toolId, schema, {
|
|
307
|
+
displayName: toolId,
|
|
308
|
+
description: `Plugin tool: ${toolId}`
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
registerHook(type, handler, name) {
|
|
313
|
+
const hookName = name ?? `plugin-hook:${type}:${Date.now().toString(36)}`;
|
|
314
|
+
registerHook(type, handler, hookName);
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
registerPluginTools(pluginName, tools) {
|
|
319
|
+
const reg = this.ensureRegistration(pluginName);
|
|
320
|
+
for (const [toolId, , schema] of tools) {
|
|
321
|
+
if (schema) {
|
|
322
|
+
registerToolParameterSchema(toolId, schema, {
|
|
323
|
+
displayName: toolId,
|
|
324
|
+
description: `Plugin tool: ${toolId}`
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
reg.tools.push(toolId);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
registerPluginHooks(pluginName, hooks) {
|
|
331
|
+
const reg = this.ensureRegistration(pluginName);
|
|
332
|
+
for (const [type, handler, name] of hooks) {
|
|
333
|
+
const hookName = name ?? `plugin-hook:${pluginName}:${type}:${reg.hooks.length}`;
|
|
334
|
+
registerHook(type, handler, hookName);
|
|
335
|
+
reg.hooks.push({ type, name: hookName });
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
getPluginRegistrations(pluginName) {
|
|
339
|
+
return this.pluginRegistrations.get(pluginName);
|
|
340
|
+
}
|
|
341
|
+
clearPluginRegistrations() {
|
|
342
|
+
this.pluginRegistrations.clear();
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
var defaultPluginRegistryManager = new PluginRegistryManager();
|
|
346
|
+
function createPluginAPI(options = {}) {
|
|
347
|
+
return defaultPluginRegistryManager.createPluginAPI(options);
|
|
348
|
+
}
|
|
349
|
+
function registerPluginTools(pluginName, tools) {
|
|
350
|
+
defaultPluginRegistryManager.registerPluginTools(pluginName, tools);
|
|
351
|
+
}
|
|
352
|
+
function registerPluginHooks(pluginName, hooks) {
|
|
353
|
+
defaultPluginRegistryManager.registerPluginHooks(pluginName, hooks);
|
|
354
|
+
}
|
|
355
|
+
function getPluginRegistrations(pluginName) {
|
|
356
|
+
return defaultPluginRegistryManager.getPluginRegistrations(pluginName);
|
|
357
|
+
}
|
|
358
|
+
function clearPluginRegistrations() {
|
|
359
|
+
defaultPluginRegistryManager.clearPluginRegistrations();
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export {
|
|
363
|
+
loadUserPermissions,
|
|
364
|
+
saveUserPermissions,
|
|
365
|
+
PERMISSIONS_TABLE_DDL,
|
|
366
|
+
TokenTracker,
|
|
367
|
+
ProviderRegistry,
|
|
368
|
+
validatePluginManifest,
|
|
369
|
+
loadPluginModule,
|
|
370
|
+
loadPluginModules,
|
|
371
|
+
unloadPlugin,
|
|
372
|
+
listPlugins,
|
|
373
|
+
getLoadedPlugin,
|
|
374
|
+
isPluginLoaded,
|
|
375
|
+
unloadAllPlugins,
|
|
376
|
+
createPluginAPI,
|
|
377
|
+
registerPluginTools,
|
|
378
|
+
registerPluginHooks,
|
|
379
|
+
getPluginRegistrations,
|
|
380
|
+
clearPluginRegistrations
|
|
381
|
+
};
|
|
382
|
+
//# sourceMappingURL=chunk-44YHBKDL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/permission/storage.ts","../src/loopAPI/tokenTracker.ts","../src/llm/providerRegistry.ts","../src/plugin/loader.ts","../src/plugin/registry.ts"],"sourcesContent":["import type { PermissionSet } from './types.js';\n\nexport interface PermissionSqlStatement {\n get(...arguments_: unknown[]): unknown;\n run(...arguments_: unknown[]): unknown;\n}\n\nexport interface PermissionSqlDatabase {\n prepare(sql: string): PermissionSqlStatement;\n}\n\nconst TABLE_NAME = 'permissions';\nconst STORAGE_KEY = 'user';\n\n/**\n * Load user-level permission set from SQLite.\n *\n * The `permissions` table stores JSON blobs keyed by `source`.\n * Returns an empty set if no persisted rules exist.\n */\nexport function loadUserPermissions(database: PermissionSqlDatabase): PermissionSet {\n try {\n const row = database\n .prepare(`SELECT rulesJson FROM ${TABLE_NAME} WHERE source = ? LIMIT 1`)\n .get(STORAGE_KEY) as { rulesJson: string } | undefined;\n\n if (row?.rulesJson) {\n return JSON.parse(row.rulesJson) as PermissionSet;\n }\n } catch {\n /* Table may not exist yet; return empty */\n }\n\n return { rules: [], source: 'user' };\n}\n\n/**\n * Persist user-level permission set to SQLite.\n *\n * Uses INSERT OR REPLACE so first-time saves work without explicit table detection.\n */\nexport function saveUserPermissions(database: PermissionSqlDatabase, set: PermissionSet): void {\n database.prepare(\n `INSERT OR REPLACE INTO ${TABLE_NAME} (source, rulesJson, updatedAt)\n VALUES (?, ?, ?)`,\n ).run(set.source, JSON.stringify(set), Date.now());\n}\n\n/** SQL statement to create the permissions table during migration. */\nexport const PERMISSIONS_TABLE_DDL = `\n CREATE TABLE IF NOT EXISTS ${TABLE_NAME} (\n source TEXT PRIMARY KEY,\n rulesJson TEXT NOT NULL,\n updatedAt INTEGER NOT NULL\n );\n`;\n","/**\n * Token counting and auto-compaction trigger.\n * Tracks token usage per conversation and triggers compaction when approaching limits.\n *\n * Based on: Claude Code autoCompact + OpenCode autoCompact@95%\n */\n\n/** Rough token estimation: ~4 chars per token (conservative) */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 3.5);\n}\n\n/** Estimate token count for a messages array */\nexport function estimateMessagesTokens(messages: Array<{ content: unknown }>): number {\n let total = 0;\n for (const message of messages) {\n const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content ?? '');\n total += estimateTokens(content);\n }\n return total;\n}\n\nexport interface TokenTrackerConfig {\n /** Maximum context window in tokens (default: 200000) */\n contextWindow?: number;\n /** Trigger compaction when usage exceeds this fraction (default: 0.90) */\n compactionThreshold?: number;\n /** Buffer tokens reserved for output (default: 16000) */\n outputBuffer?: number;\n}\n\nexport interface TokenUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n contextWindow: number;\n usagePercent: number;\n shouldCompact: boolean;\n}\n\n/**\n * Tracks token usage and decides when to trigger auto-compaction.\n */\nexport class TokenTracker {\n private promptTokens = 0;\n private completionTokens = 0;\n private readonly contextWindow: number;\n private readonly compactionThreshold: number;\n private readonly outputBuffer: number;\n private compacting = false;\n private consecutiveCompactionFailures = 0;\n private maxConsecutiveFailures = 3;\n\n constructor(config?: TokenTrackerConfig) {\n this.contextWindow = config?.contextWindow ?? 200_000;\n this.compactionThreshold = config?.compactionThreshold ?? 0.9;\n this.outputBuffer = config?.outputBuffer ?? 16_000;\n }\n\n /** Record token usage from an LLM response */\n recordUsage(promptTokens: number, completionTokens: number): void {\n this.promptTokens += promptTokens;\n this.completionTokens += completionTokens;\n }\n\n /** Manually set the prompt token count (e.g., from estimation) */\n setPromptTokens(tokens: number): void {\n this.promptTokens = tokens;\n }\n\n /** Get current usage */\n getUsage(): TokenUsage {\n const total = this.promptTokens + this.completionTokens;\n const effectiveWindow = this.contextWindow - this.outputBuffer;\n const usagePercent = total / effectiveWindow;\n return {\n promptTokens: this.promptTokens,\n completionTokens: this.completionTokens,\n totalTokens: total,\n contextWindow: this.contextWindow,\n usagePercent: Math.min(usagePercent, 1.0),\n shouldCompact: usagePercent >= this.compactionThreshold && !this.compacting,\n };\n }\n\n /** Check if auto-compaction should be triggered */\n shouldTriggerCompaction(): boolean {\n if (this.consecutiveCompactionFailures >= this.maxConsecutiveFailures) return false;\n return this.getUsage().shouldCompact;\n }\n\n /** Mark that compaction is starting */\n markCompactionStart(): void {\n this.compacting = true;\n }\n\n /** Mark that compaction succeeded — reset token counts */\n markCompactionSuccess(estimatedPostTokens: number): void {\n this.compacting = false;\n this.promptTokens = estimatedPostTokens;\n this.completionTokens = 0;\n this.consecutiveCompactionFailures = 0;\n }\n\n /** Mark that compaction failed */\n markCompactionFailure(): void {\n this.compacting = false;\n this.consecutiveCompactionFailures++;\n }\n\n /** Reset all counters */\n reset(): void {\n this.promptTokens = 0;\n this.completionTokens = 0;\n this.compacting = false;\n this.consecutiveCompactionFailures = 0;\n }\n\n /** Get a human-readable summary */\n formatUsage(): string {\n const usage = this.getUsage();\n const promptK = (usage.promptTokens / 1000).toFixed(1);\n const windowK = (usage.contextWindow / 1000).toFixed(0);\n const pct = (usage.usagePercent * 100).toFixed(1);\n return `${promptK}K/${windowK}K tokens (${pct}%)`;\n }\n}\n\n/** Interface for a compaction engine that can summarize conversation history */\nexport interface CompactionEngine {\n compact(\n messages: Array<{ role: string; content: unknown }>,\n conversationId: string,\n ): Promise<void>;\n}\n\n/**\n * Auto-compaction hook — call this after each LLM response.\n * Triggers compaction when token usage exceeds threshold.\n *\n * @returns true if compaction was triggered\n */\nexport async function maybeAutoCompact(\n tracker: TokenTracker,\n compactionEngine: CompactionEngine,\n messages: Array<{ role: string; content: unknown }>,\n conversationId: string,\n): Promise<boolean> {\n if (!tracker.shouldTriggerCompaction()) return false;\n\n tracker.markCompactionStart();\n try {\n await compactionEngine.compact(messages, conversationId);\n const estimatedPost = estimateTokens('Summary of previous conversation context.');\n tracker.markCompactionSuccess(estimatedPost);\n return true;\n } catch {\n tracker.markCompactionFailure();\n return false;\n }\n}\n","import type { ILLMProvider } from '../types.js';\n\nexport interface ProviderConfig {\n name: string;\n baseUrl?: string;\n apiKey?: string;\n}\n\nexport interface RegisteredProvider {\n provider: ILLMProvider;\n config: ProviderConfig;\n}\n\nexport class ProviderRegistry {\n private providers = new Map<string, RegisteredProvider>();\n\n register(provider: ILLMProvider, config?: Omit<ProviderConfig, 'name'>): void {\n this.providers.set(provider.name, {\n provider,\n config: {\n name: provider.name,\n baseUrl: config?.baseUrl,\n apiKey: config?.apiKey,\n },\n });\n }\n\n unregister(name: string): void {\n this.providers.delete(name);\n }\n\n get(name: string): ILLMProvider | undefined {\n return this.providers.get(name)?.provider;\n }\n\n getConfig(name: string): ProviderConfig | undefined {\n return this.providers.get(name)?.config;\n }\n\n upsertConfig(config: ProviderConfig): void {\n const existing = this.providers.get(config.name);\n if (!existing) {\n throw new Error(`Provider not found: ${config.name}`);\n }\n this.providers.set(config.name, {\n provider: existing.provider,\n config: {\n name: config.name,\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\n },\n });\n }\n\n list(): string[] {\n return Array.from(this.providers.keys()).sort();\n }\n\n listConfigs(): ProviderConfig[] {\n return this.list().map((name) => {\n const config = this.providers.get(name)?.config;\n if (!config) {\n throw new Error(`Provider config missing: ${name}`);\n }\n return { ...config };\n });\n }\n\n resolve(modelId: string): { provider: ILLMProvider; providerName: string; modelName?: string } {\n const [providerName, ...rest] = modelId.split('/');\n const registered = this.providers.get(providerName);\n if (!registered) {\n throw new Error(`Provider not found: ${providerName}`);\n }\n return {\n provider: registered.provider,\n providerName,\n modelName: rest.length > 0 ? rest.join('/') : undefined,\n };\n }\n}\n","import type { HookType } from '../loopAPI/hooks/types.js';\nimport type { LoadedPlugin, PluginManifest, PluginModule } from './types.js';\n\nconst loadedPlugins = new Map<string, LoadedPlugin>();\n\nconst hookTypes = new Set<string>([\n 'PreToolUse',\n 'PostToolUse',\n 'UserPromptSubmit',\n 'ContextCompaction',\n 'AgentStart',\n 'AgentStop',\n]);\n\nfunction isHookType(value: unknown): value is HookType {\n return typeof value === 'string' && hookTypes.has(value);\n}\n\nexport function validatePluginManifest(object: unknown): PluginManifest | null {\n if (!object || typeof object !== 'object') return null;\n const manifest = object as Record<string, unknown>;\n if (\n typeof manifest.name !== 'string' ||\n manifest.name.trim().length === 0 ||\n typeof manifest.version !== 'string' ||\n manifest.version.trim().length === 0\n ) {\n return null;\n }\n return {\n name: manifest.name.trim(),\n version: manifest.version.trim(),\n description: typeof manifest.description === 'string' ? manifest.description : '',\n exports: validateExports(manifest.exports),\n author: typeof manifest.author === 'string' ? manifest.author : undefined,\n minMemeloopVersion: typeof manifest.minMemeloopVersion === 'string' ? manifest.minMemeloopVersion : undefined,\n };\n}\n\nfunction validateExports(object: unknown): PluginManifest['exports'] {\n if (!object || typeof object !== 'object') return undefined;\n const exportsRecord = object as Record<string, unknown>;\n return {\n tools: Array.isArray(exportsRecord.tools)\n ? exportsRecord.tools.filter((tool): tool is string => typeof tool === 'string')\n : undefined,\n hooks: Array.isArray(exportsRecord.hooks) ? exportsRecord.hooks.filter(isHookType) : undefined,\n };\n}\n\nexport interface LoadPluginModuleOptions {\n manifest: PluginManifest;\n module: PluginModule;\n api?: unknown;\n source?: string;\n}\n\nexport async function loadPluginModule(\n options: LoadPluginModuleOptions,\n): Promise<LoadedPlugin | null> {\n const { manifest, module, api, source = '' } = options;\n const validManifest = validatePluginManifest(manifest);\n if (!validManifest) return null;\n\n if (loadedPlugins.has(validManifest.name)) {\n return loadedPlugins.get(validManifest.name) ?? null;\n }\n\n if (!module || typeof module.activate !== 'function') {\n return null;\n }\n\n const cleanup = await module.activate(api as never);\n const loaded: LoadedPlugin = {\n manifest: validManifest,\n source,\n module,\n cleanup: typeof cleanup === 'function' ? cleanup : undefined,\n loadedAt: new Date(),\n };\n\n loadedPlugins.set(validManifest.name, loaded);\n return loaded;\n}\n\nexport async function loadPluginModules(\n plugins: LoadPluginModuleOptions[],\n): Promise<LoadedPlugin[]> {\n const loaded: LoadedPlugin[] = [];\n for (const plugin of plugins) {\n const result = await loadPluginModule(plugin);\n if (result) loaded.push(result);\n }\n return loaded;\n}\n\nexport function unloadPlugin(name: string): boolean {\n const loaded = loadedPlugins.get(name);\n if (!loaded) return false;\n\n try {\n loaded.cleanup?.();\n } catch (error) {\n console.warn(`[plugin] Error during cleanup of \"${name}\":`, error);\n }\n\n loadedPlugins.delete(name);\n return true;\n}\n\nexport function listPlugins(): LoadedPlugin[] {\n return Array.from(loadedPlugins.values());\n}\n\nexport function getLoadedPlugin(name: string): LoadedPlugin | undefined {\n return loadedPlugins.get(name);\n}\n\nexport function isPluginLoaded(name: string): boolean {\n return loadedPlugins.has(name);\n}\n\nexport function unloadAllPlugins(): void {\n for (const name of loadedPlugins.keys()) {\n unloadPlugin(name);\n }\n}\n","/**\n * Plugin registry: bridges plugin exports to memeloop's tool and hook registries.\n *\n * Provides a `createPluginAPI()` factory that plugins call during `activate()`\n * to register their tools and hooks with the host runtime.\n *\n * Converted from module-level singletons to an instance class for test isolation\n * and multi-runtime support.\n */\n\nimport { registerHook } from '../loopAPI/hooks/registry.js';\nimport type { HookHandler, HookType } from '../loopAPI/hooks/types.js';\nimport type { ToolOperationEffect } from '../orchestration/resources.js';\nimport { registerToolParameterSchema } from '../tools/schemaRegistry.js';\nimport type { PluginAPI } from './types.js';\n\n/** Plugin API factory options. */\nexport interface PluginAPIOptions {\n toolRegistry?: {\n registerTool(\n id: string,\n impl: unknown,\n schema?: unknown,\n effect?: ToolOperationEffect,\n ): void;\n };\n logger?: PluginAPI['logger'];\n}\n\n/**\n * Track which tools/plugins belong to each plugin so we can clean up on unload.\n */\ninterface PluginRegistration {\n pluginName: string;\n tools: string[];\n hooks: Array<{ type: HookType; name: string }>;\n}\n\n/**\n * Instance-level plugin registration manager.\n */\nexport class PluginRegistryManager {\n private readonly pluginRegistrations = new Map<string, PluginRegistration>();\n\n private ensureRegistration(pluginName: string): PluginRegistration {\n const existing = this.pluginRegistrations.get(pluginName);\n if (existing) return existing;\n const reg: PluginRegistration = {\n pluginName,\n tools: [],\n hooks: [],\n };\n this.pluginRegistrations.set(pluginName, reg);\n return reg;\n }\n\n /**\n * Create a PluginAPI instance that plugins use to register their capabilities.\n */\n createPluginAPI(options: PluginAPIOptions = {}): PluginAPI {\n const toolRegistry = options.toolRegistry;\n const logger = options.logger ?? {\n debug: (...arguments_: unknown[]) => {\n console.debug('[plugin]', ...arguments_);\n },\n info: (...arguments_: unknown[]) => {\n console.info('[plugin]', ...arguments_);\n },\n warn: (...arguments_: unknown[]) => {\n console.warn('[plugin]', ...arguments_);\n },\n error: (...arguments_: unknown[]) => {\n console.error('[plugin]', ...arguments_);\n },\n };\n\n return {\n logger,\n\n registerTool(\n toolId: string,\n impl: (...arguments_: unknown[]) => unknown,\n schema?: unknown,\n effect?: ToolOperationEffect,\n ) {\n if (effect === undefined) {\n toolRegistry?.registerTool(toolId, impl, schema);\n } else {\n toolRegistry?.registerTool(toolId, impl, schema, effect);\n }\n if (schema) {\n registerToolParameterSchema(toolId, schema as object, {\n displayName: toolId,\n description: `Plugin tool: ${toolId}`,\n });\n }\n },\n\n registerHook(type: HookType, handler: HookHandler, name?: string) {\n const hookName = name ?? `plugin-hook:${type}:${Date.now().toString(36)}`;\n registerHook(type, handler, hookName);\n },\n };\n }\n\n registerPluginTools(\n pluginName: string,\n tools: Array<readonly [string, (...arguments_: unknown[]) => unknown, unknown?]>,\n ): void {\n const reg = this.ensureRegistration(pluginName);\n for (const [toolId, , schema] of tools) {\n if (schema) {\n registerToolParameterSchema(toolId, schema as object, {\n displayName: toolId,\n description: `Plugin tool: ${toolId}`,\n });\n }\n reg.tools.push(toolId);\n }\n }\n\n registerPluginHooks(\n pluginName: string,\n hooks: Array<readonly [HookType, HookHandler, string?]>,\n ): void {\n const reg = this.ensureRegistration(pluginName);\n for (const [type, handler, name] of hooks) {\n const hookName = name ?? `plugin-hook:${pluginName}:${type}:${reg.hooks.length}`;\n registerHook(type, handler, hookName);\n reg.hooks.push({ type, name: hookName });\n }\n }\n\n getPluginRegistrations(pluginName: string): PluginRegistration | undefined {\n return this.pluginRegistrations.get(pluginName);\n }\n\n clearPluginRegistrations(): void {\n this.pluginRegistrations.clear();\n }\n}\n\n// ─── Default global instance + backward-compatible function exports ───\n\nconst defaultPluginRegistryManager = new PluginRegistryManager();\n\nexport function getDefaultPluginRegistryManager(): PluginRegistryManager {\n return defaultPluginRegistryManager;\n}\n\nexport function createPluginAPI(options: PluginAPIOptions = {}): PluginAPI {\n return defaultPluginRegistryManager.createPluginAPI(options);\n}\n\nexport function registerPluginTools(\n pluginName: string,\n tools: Array<readonly [string, (...arguments_: unknown[]) => unknown, unknown?]>,\n): void {\n defaultPluginRegistryManager.registerPluginTools(pluginName, tools);\n}\n\nexport function registerPluginHooks(\n pluginName: string,\n hooks: Array<readonly [HookType, HookHandler, string?]>,\n): void {\n defaultPluginRegistryManager.registerPluginHooks(pluginName, hooks);\n}\n\nexport function getPluginRegistrations(pluginName: string): PluginRegistration | undefined {\n return defaultPluginRegistryManager.getPluginRegistrations(pluginName);\n}\n\nexport function clearPluginRegistrations(): void {\n defaultPluginRegistryManager.clearPluginRegistrations();\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// src/agent/categories.ts
|
|
2
|
+
var CATEGORY_CONFIGS = {
|
|
3
|
+
"visual-engineering": {
|
|
4
|
+
model: "default",
|
|
5
|
+
temperature: 0.3,
|
|
6
|
+
description: "UI/UX visual engineering tasks requiring precise rendering and layout"
|
|
7
|
+
},
|
|
8
|
+
ultrabrain: {
|
|
9
|
+
model: "default",
|
|
10
|
+
temperature: 0.1,
|
|
11
|
+
description: "Deep logical reasoning, architecture decisions, and complex problem-solving"
|
|
12
|
+
},
|
|
13
|
+
artistry: {
|
|
14
|
+
model: "default",
|
|
15
|
+
temperature: 0.8,
|
|
16
|
+
description: "Creative writing, design, and artistic generation tasks"
|
|
17
|
+
},
|
|
18
|
+
quick: {
|
|
19
|
+
model: "default",
|
|
20
|
+
temperature: 0.2,
|
|
21
|
+
description: "Fast, straightforward tasks with minimal deliberation needed"
|
|
22
|
+
},
|
|
23
|
+
"unspecified-low": {
|
|
24
|
+
model: "default",
|
|
25
|
+
temperature: 0.5,
|
|
26
|
+
description: "Unclassified tasks of moderate complexity and effort"
|
|
27
|
+
},
|
|
28
|
+
"unspecified-high": {
|
|
29
|
+
model: "default",
|
|
30
|
+
temperature: 0.4,
|
|
31
|
+
description: "Unclassified tasks requiring substantial effort across multiple systems"
|
|
32
|
+
},
|
|
33
|
+
writing: {
|
|
34
|
+
model: "default",
|
|
35
|
+
temperature: 0.7,
|
|
36
|
+
description: "Documentation, prose, technical writing, and content generation"
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
function getCategoryConfig(category) {
|
|
40
|
+
const config = CATEGORY_CONFIGS[category];
|
|
41
|
+
if (!config) {
|
|
42
|
+
throw new Error(`Unknown task category: ${category}`);
|
|
43
|
+
}
|
|
44
|
+
return { ...config };
|
|
45
|
+
}
|
|
46
|
+
function isTaskCategory(value) {
|
|
47
|
+
return value in CATEGORY_CONFIGS;
|
|
48
|
+
}
|
|
49
|
+
var ALL_CATEGORIES = Object.keys(CATEGORY_CONFIGS);
|
|
50
|
+
function resolveCategory(category) {
|
|
51
|
+
if (isTaskCategory(category)) {
|
|
52
|
+
return getCategoryConfig(category);
|
|
53
|
+
}
|
|
54
|
+
return getCategoryConfig("unspecified-low");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
getCategoryConfig,
|
|
59
|
+
isTaskCategory,
|
|
60
|
+
ALL_CATEGORIES,
|
|
61
|
+
resolveCategory
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=chunk-7ZDTB4VZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/agent/categories.ts"],"sourcesContent":["/**\n * Task category system for routing tasks to appropriate agent configurations.\n * Each category maps to a model, temperature, and description for delegation decisions.\n */\n\nexport type TaskCategory =\n | 'visual-engineering'\n | 'ultrabrain'\n | 'artistry'\n | 'quick'\n | 'unspecified-low'\n | 'unspecified-high'\n | 'writing';\n\nexport interface CategoryConfig {\n /** Model identifier (e.g., \"default\", \"gpt-4o\", \"claude-opus\") */\n model: string;\n /** LLM temperature (0.0 = deterministic, 1.0 = creative) */\n temperature: number;\n /** Human-readable description of the category's purpose */\n description: string;\n}\n\nconst CATEGORY_CONFIGS: Record<TaskCategory, CategoryConfig> = {\n 'visual-engineering': {\n model: 'default',\n temperature: 0.3,\n description: 'UI/UX visual engineering tasks requiring precise rendering and layout',\n },\n ultrabrain: {\n model: 'default',\n temperature: 0.1,\n description: 'Deep logical reasoning, architecture decisions, and complex problem-solving',\n },\n artistry: {\n model: 'default',\n temperature: 0.8,\n description: 'Creative writing, design, and artistic generation tasks',\n },\n quick: {\n model: 'default',\n temperature: 0.2,\n description: 'Fast, straightforward tasks with minimal deliberation needed',\n },\n 'unspecified-low': {\n model: 'default',\n temperature: 0.5,\n description: 'Unclassified tasks of moderate complexity and effort',\n },\n 'unspecified-high': {\n model: 'default',\n temperature: 0.4,\n description: 'Unclassified tasks requiring substantial effort across multiple systems',\n },\n writing: {\n model: 'default',\n temperature: 0.7,\n description: 'Documentation, prose, technical writing, and content generation',\n },\n};\n\n/**\n * Get the configuration for a task category.\n * @throws {Error} if the category is unknown\n */\nexport function getCategoryConfig(category: TaskCategory): CategoryConfig {\n const config = CATEGORY_CONFIGS[category];\n if (!config) {\n throw new Error(`Unknown task category: ${category}`);\n }\n return { ...config };\n}\n\n/**\n * Type guard: check if a string is a valid TaskCategory.\n */\nexport function isTaskCategory(value: string): value is TaskCategory {\n return value in CATEGORY_CONFIGS;\n}\n\n/** All registered category identifiers (read-only). */\nexport const ALL_CATEGORIES = Object.keys(CATEGORY_CONFIGS) as TaskCategory[];\n\n/**\n * Resolve a category string (or fallback to \"unspecified-low\").\n * Never throws; always returns a valid config.\n */\nexport function resolveCategory(category: string): CategoryConfig {\n if (isTaskCategory(category)) {\n return getCategoryConfig(category);\n }\n return getCategoryConfig('unspecified-low');\n}\n"],"mappings":";AAuBA,IAAM,mBAAyD;AAAA,EAC7D,sBAAsB;AAAA,IACpB,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,EACf;AAAA,EACA,YAAY;AAAA,IACV,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,EACf;AAAA,EACA,OAAO;AAAA,IACL,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,EACf;AAAA,EACA,mBAAmB;AAAA,IACjB,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,EACf;AAAA,EACA,oBAAoB;AAAA,IAClB,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,EACf;AAAA,EACA,SAAS;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,EACf;AACF;AAMO,SAAS,kBAAkB,UAAwC;AACxE,QAAM,SAAS,iBAAiB,QAAQ;AACxC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,0BAA0B,QAAQ,EAAE;AAAA,EACtD;AACA,SAAO,EAAE,GAAG,OAAO;AACrB;AAKO,SAAS,eAAe,OAAsC;AACnE,SAAO,SAAS;AAClB;AAGO,IAAM,iBAAiB,OAAO,KAAK,gBAAgB;AAMnD,SAAS,gBAAgB,UAAkC;AAChE,MAAI,eAAe,QAAQ,GAAG;AAC5B,WAAO,kBAAkB,QAAQ;AAAA,EACnC;AACA,SAAO,kBAAkB,iBAAiB;AAC5C;","names":[]}
|