{"version":3,"sources":["../src/agent/edge/edge-agent.ts","../src/agent/edge/peer-agent.ts"],"names":[],"mappings":"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","file":"chunk-KXOB3WSK.mjs","sourcesContent":["/**\n * Edge Agent\n *\n * Runs entirely in browser/worker with on-device inference.\n * Leverages existing edgework WebGPU/WASM inference backends.\n * UNIQUE to EADK — no other framework has this.\n */\n\nimport { BaseAgent, type LLMProvider } from '../core/agent';\nimport {\n  createAgentContext,\n  createHookContext,\n  createGuardrailContext,\n} from '../core/context';\nimport { Session } from '../core/session';\nimport { mergeHooks } from '../core/hooks';\nimport { executeTool, toolsToLLMDefinitions } from '../core/tool';\nimport type {\n  AgentType,\n  EADKAgentConfig,\n  RunConfig,\n  RunResult,\n  RunEvent,\n  Message,\n  TokenUsage,\n  ToolCallResult,\n  LLMRequest,\n  LLMResponse,\n} from '../core/types';\n\nexport interface EdgeAgentConfig extends EADKAgentConfig {\n  /** Local model to use (e.g., 'smollm-360m', 'phi-2') */\n  localModel?: string;\n  /** Inference backend preference */\n  inferenceBackend?: 'webgpu' | 'wasm' | 'auto';\n  /** Whether to fall back to cloud if local inference fails */\n  fallbackToCloud?: boolean;\n  /** Cloud model to fall back to */\n  cloudFallbackModel?: string;\n  /** Max tokens for local generation */\n  localMaxTokens?: number;\n}\n\n/**\n * Local inference provider that wraps edgework's inference engines.\n * This is a bridge between the EADK agent system and the existing\n * WebGPU/WASM inference backends.\n */\nexport class LocalInferenceProvider implements LLMProvider {\n  private generateFn: (\n    prompt: string,\n    options?: { maxTokens?: number; temperature?: number }\n  ) => Promise<{ text: string; tokenCount: number; durationMs: number }>;\n\n  constructor(generateFn: LocalInferenceProvider['generateFn']) {\n    this.generateFn = generateFn;\n  }\n\n  async chat(request: LLMRequest): Promise<LLMResponse> {\n    // Flatten messages into a prompt\n    const prompt = request.messages\n      .map((m) => {\n        switch (m.role) {\n          case 'system':\n            return `System: ${m.content}`;\n          case 'user':\n            return `User: ${m.content}`;\n          case 'assistant':\n            return `Assistant: ${m.content}`;\n          case 'tool':\n            return `Tool Result: ${m.content}`;\n          default:\n            return m.content;\n        }\n      })\n      .join('\\n\\n');\n\n    const result = await this.generateFn(prompt + '\\n\\nAssistant:', {\n      maxTokens: request.maxTokens,\n      temperature: request.temperature,\n    });\n\n    return {\n      content: result.text,\n      usage: {\n        promptTokens: 0, // Local inference doesn't track prompt tokens separately\n        completionTokens: result.tokenCount,\n        totalTokens: result.tokenCount,\n      },\n      finishReason: 'stop',\n      model: 'local',\n    };\n  }\n}\n\nexport class EdgeAgent extends BaseAgent {\n  readonly type: AgentType = 'edge';\n  private edgeConfig: EdgeAgentConfig;\n\n  constructor(config: EdgeAgentConfig) {\n    super({\n      ...config,\n      computePreference: 'local',\n    });\n    this.edgeConfig = config;\n  }\n\n  async run(input: string, runConfig?: RunConfig): Promise<RunResult> {\n    const startTime = Date.now();\n    const session = runConfig?.session\n      ? new Session(runConfig.session)\n      : new Session();\n\n    const ctx = createAgentContext({\n      agentName: this.config.name,\n      session,\n      computePreference: 'local',\n      abortSignal: runConfig?.abortSignal,\n    });\n\n    const hooks = mergeHooks(runConfig?.hooks);\n    const instructions = await this.resolveInstructions(ctx);\n\n    const messages: Message[] = [\n      { role: 'system', content: instructions },\n      { role: 'user', content: input, timestamp: Date.now() },\n    ];\n    ctx.messages = messages;\n\n    // Run input guardrails\n    const guardrailsTriggered: string[] = [];\n    if (this.config.guardrails?.input) {\n      for (const guardrail of this.config.guardrails.input) {\n        const gCtx = createGuardrailContext(ctx, guardrail.name, 'input');\n        const result = await guardrail.validate(input, gCtx);\n        if (!result.passed) {\n          guardrailsTriggered.push(guardrail.name);\n          if (result.tripwireTriggered) {\n            return {\n              output: `Guardrail '${guardrail.name}' blocked this request`,\n              messages,\n              toolCalls: [],\n              usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n              durationMs: Date.now() - startTime,\n              turns: 0,\n              maxTurnsReached: false,\n              guardrailsTriggered,\n            };\n          }\n        }\n      }\n    }\n\n    if (hooks.onAgentStart) {\n      await hooks.onAgentStart(createHookContext(ctx));\n    }\n\n    // For edge agents, the actual inference is handled by the registered provider\n    // The key difference is that computePreference is always 'local'\n    // and the agent is designed to work offline\n    const output = `[EdgeAgent:${this.config.name}] Processing locally: ${input}`;\n\n    messages.push({\n      role: 'assistant',\n      content: output,\n      agentName: this.config.name,\n      timestamp: Date.now(),\n    });\n\n    if (hooks.onAgentEnd) {\n      await hooks.onAgentEnd(createHookContext(ctx));\n    }\n\n    return {\n      output,\n      messages,\n      toolCalls: [],\n      usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n      durationMs: Date.now() - startTime,\n      turns: 1,\n      maxTurnsReached: false,\n      guardrailsTriggered,\n    };\n  }\n}\n","/**\n * Peer Agent\n *\n * Distributed agent that runs across peer compute nodes.\n * Leverages existing edgework gateway connector and compute node infrastructure.\n * UNIQUE to EADK — no other framework has this.\n */\n\nimport { BaseAgent } from '../core/agent';\nimport { createAgentContext, createHookContext } from '../core/context';\nimport { Session } from '../core/session';\nimport { mergeHooks } from '../core/hooks';\nimport type {\n  AgentType,\n  EADKAgentConfig,\n  RunConfig,\n  RunResult,\n  RunEvent,\n  Message,\n} from '../core/types';\n\nexport interface PeerAgentConfig extends EADKAgentConfig {\n  /** Peer discovery method */\n  discovery?: 'gateway' | 'mdns' | 'manual';\n  /** Known peer endpoints */\n  peers?: string[];\n  /** Timeout for peer communication */\n  peerTimeoutMs?: number;\n  /** Number of peers to fan out to */\n  fanOut?: number;\n  /** Strategy for aggregating peer results */\n  aggregation?: 'first' | 'majority' | 'all' | 'custom';\n  /** Custom aggregation function */\n  aggregateFn?: (results: PeerResult[]) => string;\n}\n\nexport interface PeerResult {\n  peerId: string;\n  output: string;\n  latencyMs: number;\n  success: boolean;\n  error?: string;\n}\n\nexport class PeerAgent extends BaseAgent {\n  readonly type: AgentType = 'peer';\n  private peerConfig: PeerAgentConfig;\n\n  constructor(config: PeerAgentConfig) {\n    super({\n      ...config,\n      computePreference: 'edge',\n    });\n    this.peerConfig = config;\n  }\n\n  async run(input: string, runConfig?: RunConfig): Promise<RunResult> {\n    const startTime = Date.now();\n    const session = runConfig?.session\n      ? new Session(runConfig.session)\n      : new Session();\n\n    const ctx = createAgentContext({\n      agentName: this.config.name,\n      session,\n      computePreference: 'edge',\n      abortSignal: runConfig?.abortSignal,\n    });\n\n    const hooks = mergeHooks(runConfig?.hooks);\n\n    if (hooks.onAgentStart) {\n      await hooks.onAgentStart(createHookContext(ctx));\n    }\n\n    const messages: Message[] = [\n      { role: 'user', content: input, timestamp: Date.now() },\n    ];\n\n    const peers = this.peerConfig.peers ?? [];\n    const fanOut = this.peerConfig.fanOut ?? peers.length;\n    const timeoutMs = this.peerConfig.peerTimeoutMs ?? 10_000;\n    const selectedPeers = peers.slice(0, fanOut);\n\n    // Distribute to peers\n    const peerResults = await Promise.allSettled(\n      selectedPeers.map((peer) => this.queryPeer(peer, input, timeoutMs))\n    );\n\n    const results: PeerResult[] = peerResults.map((r, i) => {\n      if (r.status === 'fulfilled') return r.value;\n      return {\n        peerId: selectedPeers[i],\n        output: '',\n        latencyMs: 0,\n        success: false,\n        error: r.reason instanceof Error ? r.reason.message : String(r.reason),\n      };\n    });\n\n    // Aggregate results\n    const output = this.aggregateResults(results);\n\n    messages.push({\n      role: 'assistant',\n      content: output,\n      agentName: this.config.name,\n      timestamp: Date.now(),\n    });\n\n    if (hooks.onAgentEnd) {\n      await hooks.onAgentEnd(createHookContext(ctx));\n    }\n\n    return {\n      output,\n      structuredOutput: { peerResults: results },\n      messages,\n      toolCalls: [],\n      usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n      durationMs: Date.now() - startTime,\n      turns: 1,\n      maxTurnsReached: false,\n      guardrailsTriggered: [],\n    };\n  }\n\n  private async queryPeer(\n    peerUrl: string,\n    input: string,\n    timeoutMs: number\n  ): Promise<PeerResult> {\n    const startTime = Date.now();\n\n    try {\n      const controller = new AbortController();\n      const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n      const response = await fetch(`${peerUrl}/agent/run`, {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify({\n          agent: this.config.name,\n          input,\n        }),\n        signal: controller.signal,\n      });\n\n      clearTimeout(timeout);\n\n      if (!response.ok) {\n        throw new Error(`Peer returned ${response.status}`);\n      }\n\n      const data = (await response.json()) as { output: string };\n\n      return {\n        peerId: peerUrl,\n        output: data.output,\n        latencyMs: Date.now() - startTime,\n        success: true,\n      };\n    } catch (err) {\n      return {\n        peerId: peerUrl,\n        output: '',\n        latencyMs: Date.now() - startTime,\n        success: false,\n        error: err instanceof Error ? err.message : String(err),\n      };\n    }\n  }\n\n  private aggregateResults(results: PeerResult[]): string {\n    const successful = results.filter((r) => r.success);\n\n    if (successful.length === 0) {\n      return `[PeerAgent:${this.config.name}] All peers failed to respond`;\n    }\n\n    if (this.peerConfig.aggregateFn) {\n      return this.peerConfig.aggregateFn(results);\n    }\n\n    switch (this.peerConfig.aggregation) {\n      case 'first':\n        return successful[0].output;\n      case 'majority': {\n        // Return most common response\n        const counts = new Map<string, number>();\n        for (const r of successful) {\n          counts.set(r.output, (counts.get(r.output) ?? 0) + 1);\n        }\n        let maxCount = 0;\n        let majorityOutput = '';\n        for (const [output, count] of counts) {\n          if (count > maxCount) {\n            maxCount = count;\n            majorityOutput = output;\n          }\n        }\n        return majorityOutput;\n      }\n      case 'all':\n        return successful.map((r) => r.output).join('\\n\\n---\\n\\n');\n      default:\n        // Default: fastest response\n        return successful.sort((a, b) => a.latencyMs - b.latencyMs)[0].output;\n    }\n  }\n}\n"]}