import { z } from 'zod';
import { diffSchemas } from 'json-schema-diff';
import { zodToJsonSchema } from 'zod-to-json-schema';
import { convertJsonSchemaToZod } from 'zod-from-json-schema';
import { Client as Client$1 } from '@modelcontextprotocol/sdk/client/index.js';
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
import { WebSocketClientTransport } from '@modelcontextprotocol/sdk/client/websocket.js';
import { ListToolsResultSchema } from '@modelcontextprotocol/sdk/types.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';

// src/well-known/language-model.ts
var HTTPClientTransport = class extends StreamableHTTPClientTransport {
  constructor(url, opts) {
    super(url, opts);
  }
  send(message, options) {
    const mockAction = getMockActionFor(message);
    if (mockAction?.type === "emit") {
      this.onmessage?.(mockAction.message);
      return Promise.resolve();
    }
    if (mockAction?.type === "suppress") {
      return Promise.resolve();
    }
    return super.send(message, options);
  }
};
function getMockActionFor(message) {
  const m = message;
  if (!m || typeof m !== "object" || !("method" in m)) return null;
  switch (m.method) {
    case "initialize": {
      const protocolVersion = m?.params?.protocolVersion;
      if (!protocolVersion) return null;
      return {
        type: "emit",
        message: {
          result: {
            protocolVersion,
            capabilities: { tools: {} },
            serverInfo: { name: "deco-chat-server", version: "1.0.0" }
          },
          jsonrpc: m.jsonrpc ?? "2.0",
          // @ts-expect-error - id is not typed
          id: m.id
        }
      };
    }
    case "notifications/roots/list_changed":
    case "notifications/initialized":
    case "notifications/cancelled":
    case "notifications/progress": {
      return { type: "suppress" };
    }
    default:
      return null;
  }
}

// src/core/client/mcp-client.ts
var Client = class extends Client$1 {
  constructor(_clientInfo, options) {
    super(_clientInfo, options);
  }
  async listTools(params, options) {
    const result = await this.request(
      { method: "tools/list", params },
      ListToolsResultSchema,
      options
    );
    return result;
  }
};
var createServerClient = async (mcpServer, signal, extraHeaders) => {
  const transport = createTransport(mcpServer.connection, signal, extraHeaders);
  if (!transport) {
    throw new Error("Unknown MCP connection type");
  }
  const client = new Client({
    name: mcpServer?.name ?? "MCP Client",
    version: "1.0.0"
  });
  await client.connect(transport);
  return {
    client,
    callStreamableTool: (tool, args) => {
      if (mcpServer.connection.type !== "HTTP") {
        throw new Error("HTTP connection required");
      }
      return fetch(mcpServer.connection.url + `/call-tool/${tool}`, {
        method: "POST",
        redirect: "manual",
        body: JSON.stringify(args),
        headers: {
          ...extraHeaders,
          Authorization: `Bearer ${mcpServer.connection.token}`
        }
      });
    }
  };
};
var createTransport = (connection, signal, extraHeaders) => {
  if (connection.type === "Websocket") {
    return new WebSocketClientTransport(new URL(connection.url));
  }
  if (connection.type !== "SSE" && connection.type !== "HTTP") {
    return null;
  }
  const authHeaders = connection.token ? { authorization: `Bearer ${connection.token}` } : {};
  const headers = {
    ...authHeaders,
    ...extraHeaders ?? {},
    ..."headers" in connection ? connection.headers || {} : {}
  };
  if (connection.type === "SSE") {
    const config = {
      requestInit: { headers, signal }
    };
    if (connection.token) {
      config.eventSourceInit = {
        fetch: (req, init) => {
          return fetch(req, {
            ...init,
            headers: {
              ...headers,
              Accept: "text/event-stream"
            },
            signal
          });
        }
      };
    }
    return new SSEClientTransport(new URL(connection.url), config);
  }
  return new HTTPClientTransport(new URL(connection.url), {
    requestInit: {
      headers,
      signal,
      // @ts-ignore - this is a valid option for fetch
      credentials: "include"
    }
  });
};

// src/core/client/proxy.ts
var safeParse = (content) => {
  try {
    return JSON.parse(content);
  } catch {
    return content;
  }
};
var toolsMap = /* @__PURE__ */ new Map();
function createMCPClientProxy(options) {
  return new Proxy({}, {
    get(_, name) {
      if (name === "toJSON") {
        return null;
      }
      if (typeof name !== "string") {
        throw new Error("Name must be a string");
      }
      async function callToolFn(args) {
        const debugId = options?.debugId?.();
        const extraHeaders = debugId ? { "x-trace-debug-id": debugId } : void 0;
        const { client, callStreamableTool } = await createServerClient(
          { connection: options.connection },
          void 0,
          extraHeaders
        );
        if (options?.streamable?.[String(name)]) {
          return callStreamableTool(String(name), args);
        }
        const { structuredContent, isError, content } = await client.callTool(
          {
            name: String(name),
            arguments: args
          },
          void 0,
          {
            timeout: 3e6
          }
        );
        if (isError) {
          const maybeErrorMessage = content?.[0]?.text;
          const error = typeof maybeErrorMessage === "string" ? safeParse(maybeErrorMessage) : null;
          const throwableError = error?.code && typeof options?.getErrorByStatusCode === "function" ? options.getErrorByStatusCode(
            error.code,
            error.message,
            error.traceId
          ) : null;
          if (throwableError) {
            throw throwableError;
          }
          throw new Error(
            `Tool ${String(name)} returned an error: ${JSON.stringify(
              structuredContent ?? content
            )}`
          );
        }
        return structuredContent;
      }
      const listToolsFn = async () => {
        const { client } = await createServerClient({
          connection: options.connection
        });
        const { tools } = await client.listTools();
        return tools;
      };
      async function listToolsOnce() {
        const conn = options.connection;
        const key = JSON.stringify(conn);
        try {
          if (!toolsMap.has(key)) {
            toolsMap.set(key, listToolsFn());
          }
          return await toolsMap.get(key);
        } catch (error) {
          console.error("Failed to list tools", error);
          toolsMap.delete(key);
          return;
        }
      }
      callToolFn.asTool = async () => {
        const tools = await listToolsOnce() ?? [];
        const tool = tools.find((t) => t.name === name);
        if (!tool) {
          throw new Error(`Tool ${name} not found`);
        }
        return {
          ...tool,
          id: tool.name,
          inputSchema: tool.inputSchema ? convertJsonSchemaToZod(tool.inputSchema) : void 0,
          outputSchema: tool.outputSchema ? convertJsonSchemaToZod(tool.outputSchema) : void 0,
          execute: (input) => {
            return callToolFn(input.context);
          }
        };
      };
      return callToolFn;
    }
  });
}

// src/core/client/mcp.ts
new Proxy(
  {},
  {
    get(_, name) {
      if (name === "toJSON") {
        return null;
      }
      if (name === "forConnection") {
        return (connection) => createMCPFetchStub({
          connection
        });
      }
      return global[name];
    }
  }
);
function createMCPFetchStub(options) {
  return createMCPClientProxy(options);
}

// src/core/binder.ts
function normalizeSchema(schema) {
  if (!schema) return void 0;
  if (schema._def) {
    const jsonSchema2 = zodToJsonSchema(schema, {
      // Don't add additionalProperties: false to allow structural compatibility
      $refStrategy: "none"
    });
    if (jsonSchema2.type === "object") {
      delete jsonSchema2.additionalProperties;
    }
    return jsonSchema2;
  }
  const jsonSchema = schema;
  if (jsonSchema.type === "object" && "additionalProperties" in jsonSchema) {
    const copy = { ...jsonSchema };
    delete copy.additionalProperties;
    return copy;
  }
  return jsonSchema;
}
var bindingClient = (binder) => {
  return {
    ...createBindingChecker(binder),
    forConnection: (mcpConnection) => {
      return createMCPFetchStub({
        connection: mcpConnection,
        streamable: binder.reduce(
          (acc, tool) => {
            acc[tool.name] = tool.streamable === true;
            return acc;
          },
          {}
        )
      });
    }
  };
};
function createBindingChecker(binderTools) {
  return {
    isImplementedBy: async (tools) => {
      for (const binderTool of binderTools) {
        const pattern = typeof binderTool.name === "string" ? new RegExp(`^${binderTool.name}$`) : binderTool.name;
        const matchedTool = tools.find((t) => pattern.test(t.name));
        if (!matchedTool && binderTool.opt) {
          continue;
        }
        if (!matchedTool) {
          return false;
        }
        const binderInputSchema = normalizeSchema(binderTool.inputSchema);
        const toolInputSchema = normalizeSchema(matchedTool.inputSchema);
        if (binderInputSchema && toolInputSchema) {
          try {
            const inputDiff = await diffSchemas({
              sourceSchema: binderInputSchema,
              destinationSchema: toolInputSchema
            });
            if (inputDiff.removalsFound) {
              return false;
            }
          } catch (error) {
            console.error("Schema diff failed", error);
            return false;
          }
        } else if (binderInputSchema && !toolInputSchema) {
          return false;
        }
        const binderOutputSchema = normalizeSchema(binderTool.outputSchema);
        const toolOutputSchema = normalizeSchema(matchedTool.outputSchema);
        if (binderOutputSchema && toolOutputSchema) {
          try {
            const outputDiff = await diffSchemas({
              sourceSchema: binderOutputSchema,
              destinationSchema: toolOutputSchema
            });
            if (outputDiff.removalsFound) {
              return false;
            }
          } catch (error) {
            console.error("Schema diff failed", error);
            return false;
          }
        } else if (binderOutputSchema && !toolOutputSchema) {
          return false;
        }
      }
      return true;
    }
  };
}
var BaseCollectionEntitySchema = z.object({
  id: z.string().describe("Unique identifier for the entity"),
  title: z.string().describe("Human-readable title for the entity"),
  created_at: z.string().datetime(),
  updated_at: z.string().datetime(),
  created_by: z.string().optional(),
  updated_by: z.string().optional()
});
var ComparisonExpressionSchema = z.object({
  field: z.array(z.string()),
  operator: z.enum(["eq", "gt", "gte", "lt", "lte", "in", "like", "contains"]),
  value: z.unknown()
});
var WhereExpressionSchema = z.union([
  ComparisonExpressionSchema,
  z.object({
    operator: z.enum(["and", "or", "not"]),
    conditions: z.array(ComparisonExpressionSchema)
  })
]);
var OrderByExpressionSchema = z.object({
  field: z.array(z.string()),
  direction: z.enum(["asc", "desc"]),
  nulls: z.enum(["first", "last"]).optional()
});
var CollectionListInputSchema = z.object({
  where: WhereExpressionSchema.optional().describe("Filter expression"),
  orderBy: z.array(OrderByExpressionSchema).optional().describe("Sort expressions"),
  limit: z.number().int().min(1).max(1e3).optional().describe("Maximum number of items to return"),
  offset: z.number().int().min(0).optional().describe("Number of items to skip")
});
function createCollectionListOutputSchema(entitySchema) {
  return z.object({
    items: z.array(entitySchema).describe("Array of collection items"),
    totalCount: z.number().int().min(0).optional().describe("Total number of matching items (if available)"),
    hasMore: z.boolean().optional().describe("Whether there are more items available")
  });
}
var CollectionGetInputSchema = z.object({
  id: z.string().describe("ID of the entity to retrieve")
});
function createCollectionGetOutputSchema(entitySchema) {
  return z.object({
    item: entitySchema.nullable().describe("The retrieved item, or null if not found")
  });
}
z.object({
  id: z.string().describe("ID of the entity to delete")
});
function createCollectionBindings(collectionName, entitySchema, options) {
  const upperName = collectionName.toUpperCase();
  const bindings = [
    {
      name: `COLLECTION_${upperName}_LIST`,
      inputSchema: CollectionListInputSchema,
      outputSchema: createCollectionListOutputSchema(entitySchema)
    },
    {
      name: `COLLECTION_${upperName}_GET`,
      inputSchema: CollectionGetInputSchema,
      outputSchema: createCollectionGetOutputSchema(entitySchema)
    }
  ];
  return bindings;
}

// src/well-known/models.ts
var ModelSchema = BaseCollectionEntitySchema.extend({
  // Model-specific fields
  logo: z.string().nullable(),
  description: z.string().nullable(),
  capabilities: z.array(z.string()),
  limits: z.object({
    contextWindow: z.number(),
    maxOutputTokens: z.number()
  }).nullable(),
  costs: z.object({
    input: z.number(),
    output: z.number()
  }).nullable(),
  // Provider information
  provider: z.enum([
    "openai",
    "anthropic",
    "google",
    "xai",
    "deepseek",
    "openai-compatible",
    "openrouter"
  ]).nullable(),
  // Streaming endpoint information
  endpoint: z.object({
    url: z.string().url(),
    method: z.string().default("POST"),
    contentType: z.string().default("application/json"),
    stream: z.boolean().default(true)
  }).nullable()
});
var MODELS_COLLECTION_BINDING = createCollectionBindings(
  "models",
  ModelSchema);
var MODELS_BINDING = [
  ...MODELS_COLLECTION_BINDING
];

// src/well-known/language-model.ts
var LanguageModelCallOptionsSchema = z.object({
  // Core parameters
  prompt: z.any().describe(
    "A language mode prompt is a standardized prompt type (messages, system, etc.)"
  ),
  // Generation parameters
  maxOutputTokens: z.number().optional().describe("Maximum number of tokens to generate"),
  temperature: z.number().optional().describe(
    "Temperature setting. The range depends on the provider and model"
  ),
  topP: z.number().optional().describe("Nucleus sampling parameter"),
  topK: z.number().optional().describe(
    "Only sample from the top K options for each subsequent token. Used to remove long tail low probability responses"
  ),
  presencePenalty: z.number().optional().describe(
    "Presence penalty setting. It affects the likelihood of the model to repeat information that is already in the prompt"
  ),
  frequencyPenalty: z.number().optional().describe(
    "Frequency penalty setting. It affects the likelihood of the model to repeatedly use the same words or phrases"
  ),
  seed: z.number().optional().describe(
    "The seed (integer) to use for random sampling. If set and supported by the model, calls will generate deterministic results"
  ),
  // Stop sequences
  stopSequences: z.array(z.string()).optional().describe(
    "Stop sequences. If set, the model will stop generating text when one of the stop sequences is generated"
  ),
  // Response format
  responseFormat: z.union([
    z.object({ type: z.literal("text") }),
    z.object({
      type: z.literal("json"),
      schema: z.any().optional().describe("JSON schema that the generated output should conform to"),
      name: z.string().optional().describe("Name of output that should be generated"),
      description: z.string().optional().describe("Description of the output that should be generated")
    })
  ]).optional().describe(
    "Response format. The output can either be text or JSON. Default is text"
  ),
  // Tools
  tools: z.array(z.any()).optional().describe("The tools that are available for the model"),
  toolChoice: z.any().optional().describe("Specifies how the tool should be selected. Defaults to 'auto'"),
  // Stream options
  includeRawChunks: z.boolean().optional().describe(
    "Include raw chunks in the stream. Only applicable for streaming calls"
  ),
  // Abort signal
  abortSignal: z.any().optional().describe("Abort signal for cancelling the operation"),
  // Additional options
  headers: z.record(z.string(), z.union([z.string(), z.undefined()])).optional().describe("Additional HTTP headers to be sent with the request"),
  providerOptions: z.any().optional().describe("Additional provider-specific options")
});
var LanguageModelGenerateOutputSchema = z.object({
  // Ordered content that the model has generated
  content: z.array(z.any()).describe(
    "Ordered content that the model has generated (text, tool-calls, reasoning, files, sources)"
  ),
  // Finish reason (required)
  finishReason: z.enum([
    "stop",
    "length",
    "content-filter",
    "tool-calls",
    "error",
    "other",
    "unknown"
  ]).describe("Reason why generation stopped"),
  // Usage information (required)
  usage: z.object({
    inputTokens: z.number().optional(),
    outputTokens: z.number().optional(),
    totalTokens: z.number().optional(),
    reasoningTokens: z.number().optional()
  }).passthrough().transform((val) => ({
    inputTokens: val.inputTokens,
    outputTokens: val.outputTokens,
    totalTokens: val.totalTokens,
    reasoningTokens: val.reasoningTokens,
    ...val
  })).describe("Usage information for the language model call"),
  // Provider metadata
  providerMetadata: z.any().optional().describe("Additional provider-specific metadata"),
  // Request information for telemetry and debugging
  request: z.object({
    body: z.any().optional().describe("Request HTTP body sent to the provider API")
  }).optional().describe("Optional request information for telemetry and debugging"),
  // Response information for telemetry and debugging
  response: z.object({
    id: z.string().optional().describe("ID for the generated response"),
    timestamp: z.date().optional().describe("Timestamp for the start of the generated response"),
    modelId: z.string().optional().describe("The ID of the response model that was used"),
    headers: z.record(z.string(), z.string()).optional().describe("Response headers"),
    body: z.any().optional().describe("Response HTTP body")
  }).optional().describe("Optional response information for telemetry and debugging"),
  // Warnings for the call (required)
  warnings: z.array(z.any()).describe("Warnings for the call, e.g. unsupported settings")
});
var LanguageModelStreamOutputSchema = z.object({
  // Stream of language model output parts
  stream: z.any().describe("ReadableStream of LanguageModelV2StreamPart"),
  // Request information for telemetry and debugging
  request: z.object({
    body: z.any().optional().describe("Request HTTP body sent to the provider API")
  }).optional().describe("Optional request information for telemetry and debugging"),
  // Response information
  response: z.object({
    headers: z.record(z.string(), z.string()).optional().describe("Response headers")
  }).optional().describe("Optional response data")
});
var LanguageModelMetadataSchema = z.object({
  supportedUrls: z.record(z.string(), z.array(z.string())).describe("Supported URL patterns by media type for the provider")
});
var ModelSchema2 = z.object({
  modelId: z.string().describe("The ID of the model"),
  // Model-specific fields
  logo: z.string().nullable(),
  description: z.string().nullable(),
  capabilities: z.array(z.string()),
  limits: z.object({
    contextWindow: z.number(),
    maxOutputTokens: z.number()
  }).nullable(),
  costs: z.object({
    input: z.number(),
    output: z.number()
  }).nullable(),
  // Provider information
  provider: z.enum([
    "openai",
    "anthropic",
    "google",
    "xai",
    "deepseek",
    "openai-compatible",
    "openrouter"
  ]).nullable()
});
var LanguageModelInputSchema = z.object({
  modelId: z.string().describe("The ID of the model"),
  callOptions: LanguageModelCallOptionsSchema
});
var LANGUAGE_MODEL_BINDING = [
  {
    name: "LLM_METADATA",
    inputSchema: z.object({
      modelId: z.string().describe("The ID of the model")
    }),
    outputSchema: LanguageModelMetadataSchema
  },
  {
    name: "LLM_DO_STREAM",
    inputSchema: LanguageModelInputSchema,
    streamable: true
  },
  {
    name: "LLM_DO_GENERATE",
    inputSchema: LanguageModelInputSchema,
    outputSchema: LanguageModelGenerateOutputSchema
  },
  ...MODELS_BINDING
];
var LanguageModelBinding = bindingClient(LANGUAGE_MODEL_BINDING);

export { LANGUAGE_MODEL_BINDING, LanguageModelBinding, LanguageModelCallOptionsSchema, LanguageModelGenerateOutputSchema, LanguageModelInputSchema, LanguageModelMetadataSchema, LanguageModelStreamOutputSchema, ModelSchema2 as ModelSchema };
//# sourceMappingURL=language-model.js.map
//# sourceMappingURL=language-model.js.map