// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
//   protoc-gen-ts_proto  v2.11.8
//   protoc               v3.19.1
// source: chat.proto

/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import {
  type CallOptions,
  type ChannelCredentials,
  Client,
  type ClientOptions,
  type ClientReadableStream,
  type handleServerStreamingCall,
  makeGenericClientConstructor,
  type Metadata,
  type UntypedServiceImplementation,
} from "@grpc/grpc-js";
import Long from "long";
import { ChatMessage, Principal, ToolDescriptor } from "./common";
import { Struct } from "./google/protobuf/struct";

export interface RagOptions {
  enabled: boolean;
  /** 0 = use server default */
  topK: number;
}

export interface ChatRequest {
  messages: ChatMessage[];
  conversationId: string;
  model: string;
  provider: string;
  toolsAvailable: ToolDescriptor[];
  rag?:
    | RagOptions
    | undefined;
  /**
   * Optional for JWT auth (overridden by JWT claims). Required for
   * API-key auth — but API-key callers should use the HTTP surface.
   */
  principal?: Principal | undefined;
}

export interface TokenEvent {
  token: string;
  value: string;
}

export interface CitationEvent {
  chunkId: string;
  documentId: string;
  source: string;
  score: number;
  snippet: string;
}

export interface AgentStepEvent {
  agent: string;
  step: string;
  stepId: string;
}

export interface ToolCallEvent {
  callId: string;
  name: string;
  args?: { [key: string]: any } | undefined;
}

export interface ErrorEvent {
  code: string;
  message: string;
  retriable: boolean;
}

export interface DoneStats {
  tokensIn: number;
  tokensOut: number;
  chunksRetrieved: number;
}

export interface DoneEvent {
  stats?: DoneStats | undefined;
}

/**
 * Polymorphic stream payload. Mirrors the SSE shapes from the OpenAPI
 * surface (kept side-by-side for third-party callers). gRPC's `oneof`
 * gives us a tagged union without the SSE JSON discriminator.
 */
export interface ChatEvent {
  token?: TokenEvent | undefined;
  citation?: CitationEvent | undefined;
  agentStep?: AgentStepEvent | undefined;
  toolCall?: ToolCallEvent | undefined;
  error?: ErrorEvent | undefined;
  done?: DoneEvent | undefined;
}

function createBaseRagOptions(): RagOptions {
  return { enabled: false, topK: 0 };
}

export const RagOptions: MessageFns<RagOptions> = {
  encode(message: RagOptions, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
    if (message.enabled !== false) {
      writer.uint32(8).bool(message.enabled);
    }
    if (message.topK !== 0) {
      writer.uint32(16).int32(message.topK);
    }
    return writer;
  },

  decode(input: BinaryReader | Uint8Array, length?: number): RagOptions {
    const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
    const end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseRagOptions();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1: {
          if (tag !== 8) {
            break;
          }

          message.enabled = reader.bool();
          continue;
        }
        case 2: {
          if (tag !== 16) {
            break;
          }

          message.topK = reader.int32();
          continue;
        }
      }
      if ((tag & 7) === 4 || tag === 0) {
        break;
      }
      reader.skip(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): RagOptions {
    return {
      enabled: isSet(object.enabled) ? globalThis.Boolean(object.enabled) : false,
      topK: isSet(object.topK)
        ? globalThis.Number(object.topK)
        : isSet(object.top_k)
        ? globalThis.Number(object.top_k)
        : 0,
    };
  },

  toJSON(message: RagOptions): unknown {
    const obj: any = {};
    if (message.enabled !== false) {
      obj.enabled = message.enabled;
    }
    if (message.topK !== 0) {
      obj.topK = Math.round(message.topK);
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<RagOptions>, I>>(base?: I): RagOptions {
    return RagOptions.fromPartial(base ?? ({} as any));
  },
  fromPartial<I extends Exact<DeepPartial<RagOptions>, I>>(object: I): RagOptions {
    const message = createBaseRagOptions();
    message.enabled = object.enabled ?? false;
    message.topK = object.topK ?? 0;
    return message;
  },
};

function createBaseChatRequest(): ChatRequest {
  return {
    messages: [],
    conversationId: "",
    model: "",
    provider: "",
    toolsAvailable: [],
    rag: undefined,
    principal: undefined,
  };
}

export const ChatRequest: MessageFns<ChatRequest> = {
  encode(message: ChatRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
    for (const v of message.messages) {
      ChatMessage.encode(v!, writer.uint32(10).fork()).join();
    }
    if (message.conversationId !== "") {
      writer.uint32(18).string(message.conversationId);
    }
    if (message.model !== "") {
      writer.uint32(26).string(message.model);
    }
    if (message.provider !== "") {
      writer.uint32(34).string(message.provider);
    }
    for (const v of message.toolsAvailable) {
      ToolDescriptor.encode(v!, writer.uint32(42).fork()).join();
    }
    if (message.rag !== undefined) {
      RagOptions.encode(message.rag, writer.uint32(50).fork()).join();
    }
    if (message.principal !== undefined) {
      Principal.encode(message.principal, writer.uint32(58).fork()).join();
    }
    return writer;
  },

  decode(input: BinaryReader | Uint8Array, length?: number): ChatRequest {
    const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
    const end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseChatRequest();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1: {
          if (tag !== 10) {
            break;
          }

          message.messages.push(ChatMessage.decode(reader, reader.uint32()));
          continue;
        }
        case 2: {
          if (tag !== 18) {
            break;
          }

          message.conversationId = reader.string();
          continue;
        }
        case 3: {
          if (tag !== 26) {
            break;
          }

          message.model = reader.string();
          continue;
        }
        case 4: {
          if (tag !== 34) {
            break;
          }

          message.provider = reader.string();
          continue;
        }
        case 5: {
          if (tag !== 42) {
            break;
          }

          message.toolsAvailable.push(ToolDescriptor.decode(reader, reader.uint32()));
          continue;
        }
        case 6: {
          if (tag !== 50) {
            break;
          }

          message.rag = RagOptions.decode(reader, reader.uint32());
          continue;
        }
        case 7: {
          if (tag !== 58) {
            break;
          }

          message.principal = Principal.decode(reader, reader.uint32());
          continue;
        }
      }
      if ((tag & 7) === 4 || tag === 0) {
        break;
      }
      reader.skip(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): ChatRequest {
    return {
      messages: globalThis.Array.isArray(object?.messages)
        ? object.messages.map((e: any) => ChatMessage.fromJSON(e))
        : [],
      conversationId: isSet(object.conversationId)
        ? globalThis.String(object.conversationId)
        : isSet(object.conversation_id)
        ? globalThis.String(object.conversation_id)
        : "",
      model: isSet(object.model) ? globalThis.String(object.model) : "",
      provider: isSet(object.provider) ? globalThis.String(object.provider) : "",
      toolsAvailable: globalThis.Array.isArray(object?.toolsAvailable)
        ? object.toolsAvailable.map((e: any) => ToolDescriptor.fromJSON(e))
        : globalThis.Array.isArray(object?.tools_available)
        ? object.tools_available.map((e: any) => ToolDescriptor.fromJSON(e))
        : [],
      rag: isSet(object.rag) ? RagOptions.fromJSON(object.rag) : undefined,
      principal: isSet(object.principal) ? Principal.fromJSON(object.principal) : undefined,
    };
  },

  toJSON(message: ChatRequest): unknown {
    const obj: any = {};
    if (message.messages?.length) {
      obj.messages = message.messages.map((e) => ChatMessage.toJSON(e));
    }
    if (message.conversationId !== "") {
      obj.conversationId = message.conversationId;
    }
    if (message.model !== "") {
      obj.model = message.model;
    }
    if (message.provider !== "") {
      obj.provider = message.provider;
    }
    if (message.toolsAvailable?.length) {
      obj.toolsAvailable = message.toolsAvailable.map((e) => ToolDescriptor.toJSON(e));
    }
    if (message.rag !== undefined) {
      obj.rag = RagOptions.toJSON(message.rag);
    }
    if (message.principal !== undefined) {
      obj.principal = Principal.toJSON(message.principal);
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<ChatRequest>, I>>(base?: I): ChatRequest {
    return ChatRequest.fromPartial(base ?? ({} as any));
  },
  fromPartial<I extends Exact<DeepPartial<ChatRequest>, I>>(object: I): ChatRequest {
    const message = createBaseChatRequest();
    message.messages = object.messages?.map((e) => ChatMessage.fromPartial(e)) || [];
    message.conversationId = object.conversationId ?? "";
    message.model = object.model ?? "";
    message.provider = object.provider ?? "";
    message.toolsAvailable = object.toolsAvailable?.map((e) => ToolDescriptor.fromPartial(e)) || [];
    message.rag = (object.rag !== undefined && object.rag !== null) ? RagOptions.fromPartial(object.rag) : undefined;
    message.principal = (object.principal !== undefined && object.principal !== null)
      ? Principal.fromPartial(object.principal)
      : undefined;
    return message;
  },
};

function createBaseTokenEvent(): TokenEvent {
  return { token: "", value: "" };
}

export const TokenEvent: MessageFns<TokenEvent> = {
  encode(message: TokenEvent, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
    if (message.token !== "") {
      writer.uint32(10).string(message.token);
    }
    if (message.value !== "") {
      writer.uint32(18).string(message.value);
    }
    return writer;
  },

  decode(input: BinaryReader | Uint8Array, length?: number): TokenEvent {
    const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
    const end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseTokenEvent();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1: {
          if (tag !== 10) {
            break;
          }

          message.token = reader.string();
          continue;
        }
        case 2: {
          if (tag !== 18) {
            break;
          }

          message.value = reader.string();
          continue;
        }
      }
      if ((tag & 7) === 4 || tag === 0) {
        break;
      }
      reader.skip(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): TokenEvent {
    return {
      token: isSet(object.token) ? globalThis.String(object.token) : "",
      value: isSet(object.value) ? globalThis.String(object.value) : "",
    };
  },

  toJSON(message: TokenEvent): unknown {
    const obj: any = {};
    if (message.token !== "") {
      obj.token = message.token;
    }
    if (message.value !== "") {
      obj.value = message.value;
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<TokenEvent>, I>>(base?: I): TokenEvent {
    return TokenEvent.fromPartial(base ?? ({} as any));
  },
  fromPartial<I extends Exact<DeepPartial<TokenEvent>, I>>(object: I): TokenEvent {
    const message = createBaseTokenEvent();
    message.token = object.token ?? "";
    message.value = object.value ?? "";
    return message;
  },
};

function createBaseCitationEvent(): CitationEvent {
  return { chunkId: "", documentId: "", source: "", score: 0, snippet: "" };
}

export const CitationEvent: MessageFns<CitationEvent> = {
  encode(message: CitationEvent, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
    if (message.chunkId !== "") {
      writer.uint32(10).string(message.chunkId);
    }
    if (message.documentId !== "") {
      writer.uint32(18).string(message.documentId);
    }
    if (message.source !== "") {
      writer.uint32(26).string(message.source);
    }
    if (message.score !== 0) {
      writer.uint32(33).double(message.score);
    }
    if (message.snippet !== "") {
      writer.uint32(42).string(message.snippet);
    }
    return writer;
  },

  decode(input: BinaryReader | Uint8Array, length?: number): CitationEvent {
    const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
    const end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseCitationEvent();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1: {
          if (tag !== 10) {
            break;
          }

          message.chunkId = reader.string();
          continue;
        }
        case 2: {
          if (tag !== 18) {
            break;
          }

          message.documentId = reader.string();
          continue;
        }
        case 3: {
          if (tag !== 26) {
            break;
          }

          message.source = reader.string();
          continue;
        }
        case 4: {
          if (tag !== 33) {
            break;
          }

          message.score = reader.double();
          continue;
        }
        case 5: {
          if (tag !== 42) {
            break;
          }

          message.snippet = reader.string();
          continue;
        }
      }
      if ((tag & 7) === 4 || tag === 0) {
        break;
      }
      reader.skip(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): CitationEvent {
    return {
      chunkId: isSet(object.chunkId)
        ? globalThis.String(object.chunkId)
        : isSet(object.chunk_id)
        ? globalThis.String(object.chunk_id)
        : "",
      documentId: isSet(object.documentId)
        ? globalThis.String(object.documentId)
        : isSet(object.document_id)
        ? globalThis.String(object.document_id)
        : "",
      source: isSet(object.source) ? globalThis.String(object.source) : "",
      score: isSet(object.score) ? globalThis.Number(object.score) : 0,
      snippet: isSet(object.snippet) ? globalThis.String(object.snippet) : "",
    };
  },

  toJSON(message: CitationEvent): unknown {
    const obj: any = {};
    if (message.chunkId !== "") {
      obj.chunkId = message.chunkId;
    }
    if (message.documentId !== "") {
      obj.documentId = message.documentId;
    }
    if (message.source !== "") {
      obj.source = message.source;
    }
    if (message.score !== 0) {
      obj.score = message.score;
    }
    if (message.snippet !== "") {
      obj.snippet = message.snippet;
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<CitationEvent>, I>>(base?: I): CitationEvent {
    return CitationEvent.fromPartial(base ?? ({} as any));
  },
  fromPartial<I extends Exact<DeepPartial<CitationEvent>, I>>(object: I): CitationEvent {
    const message = createBaseCitationEvent();
    message.chunkId = object.chunkId ?? "";
    message.documentId = object.documentId ?? "";
    message.source = object.source ?? "";
    message.score = object.score ?? 0;
    message.snippet = object.snippet ?? "";
    return message;
  },
};

function createBaseAgentStepEvent(): AgentStepEvent {
  return { agent: "", step: "", stepId: "" };
}

export const AgentStepEvent: MessageFns<AgentStepEvent> = {
  encode(message: AgentStepEvent, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
    if (message.agent !== "") {
      writer.uint32(10).string(message.agent);
    }
    if (message.step !== "") {
      writer.uint32(18).string(message.step);
    }
    if (message.stepId !== "") {
      writer.uint32(26).string(message.stepId);
    }
    return writer;
  },

  decode(input: BinaryReader | Uint8Array, length?: number): AgentStepEvent {
    const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
    const end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseAgentStepEvent();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1: {
          if (tag !== 10) {
            break;
          }

          message.agent = reader.string();
          continue;
        }
        case 2: {
          if (tag !== 18) {
            break;
          }

          message.step = reader.string();
          continue;
        }
        case 3: {
          if (tag !== 26) {
            break;
          }

          message.stepId = reader.string();
          continue;
        }
      }
      if ((tag & 7) === 4 || tag === 0) {
        break;
      }
      reader.skip(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): AgentStepEvent {
    return {
      agent: isSet(object.agent) ? globalThis.String(object.agent) : "",
      step: isSet(object.step) ? globalThis.String(object.step) : "",
      stepId: isSet(object.stepId)
        ? globalThis.String(object.stepId)
        : isSet(object.step_id)
        ? globalThis.String(object.step_id)
        : "",
    };
  },

  toJSON(message: AgentStepEvent): unknown {
    const obj: any = {};
    if (message.agent !== "") {
      obj.agent = message.agent;
    }
    if (message.step !== "") {
      obj.step = message.step;
    }
    if (message.stepId !== "") {
      obj.stepId = message.stepId;
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<AgentStepEvent>, I>>(base?: I): AgentStepEvent {
    return AgentStepEvent.fromPartial(base ?? ({} as any));
  },
  fromPartial<I extends Exact<DeepPartial<AgentStepEvent>, I>>(object: I): AgentStepEvent {
    const message = createBaseAgentStepEvent();
    message.agent = object.agent ?? "";
    message.step = object.step ?? "";
    message.stepId = object.stepId ?? "";
    return message;
  },
};

function createBaseToolCallEvent(): ToolCallEvent {
  return { callId: "", name: "", args: undefined };
}

export const ToolCallEvent: MessageFns<ToolCallEvent> = {
  encode(message: ToolCallEvent, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
    if (message.callId !== "") {
      writer.uint32(10).string(message.callId);
    }
    if (message.name !== "") {
      writer.uint32(18).string(message.name);
    }
    if (message.args !== undefined) {
      Struct.encode(Struct.wrap(message.args), writer.uint32(26).fork()).join();
    }
    return writer;
  },

  decode(input: BinaryReader | Uint8Array, length?: number): ToolCallEvent {
    const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
    const end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseToolCallEvent();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1: {
          if (tag !== 10) {
            break;
          }

          message.callId = reader.string();
          continue;
        }
        case 2: {
          if (tag !== 18) {
            break;
          }

          message.name = reader.string();
          continue;
        }
        case 3: {
          if (tag !== 26) {
            break;
          }

          message.args = Struct.unwrap(Struct.decode(reader, reader.uint32()));
          continue;
        }
      }
      if ((tag & 7) === 4 || tag === 0) {
        break;
      }
      reader.skip(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): ToolCallEvent {
    return {
      callId: isSet(object.callId)
        ? globalThis.String(object.callId)
        : isSet(object.call_id)
        ? globalThis.String(object.call_id)
        : "",
      name: isSet(object.name) ? globalThis.String(object.name) : "",
      args: isObject(object.args) ? object.args : undefined,
    };
  },

  toJSON(message: ToolCallEvent): unknown {
    const obj: any = {};
    if (message.callId !== "") {
      obj.callId = message.callId;
    }
    if (message.name !== "") {
      obj.name = message.name;
    }
    if (message.args !== undefined) {
      obj.args = message.args;
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<ToolCallEvent>, I>>(base?: I): ToolCallEvent {
    return ToolCallEvent.fromPartial(base ?? ({} as any));
  },
  fromPartial<I extends Exact<DeepPartial<ToolCallEvent>, I>>(object: I): ToolCallEvent {
    const message = createBaseToolCallEvent();
    message.callId = object.callId ?? "";
    message.name = object.name ?? "";
    message.args = object.args ?? undefined;
    return message;
  },
};

function createBaseErrorEvent(): ErrorEvent {
  return { code: "", message: "", retriable: false };
}

export const ErrorEvent: MessageFns<ErrorEvent> = {
  encode(message: ErrorEvent, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
    if (message.code !== "") {
      writer.uint32(10).string(message.code);
    }
    if (message.message !== "") {
      writer.uint32(18).string(message.message);
    }
    if (message.retriable !== false) {
      writer.uint32(24).bool(message.retriable);
    }
    return writer;
  },

  decode(input: BinaryReader | Uint8Array, length?: number): ErrorEvent {
    const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
    const end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseErrorEvent();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1: {
          if (tag !== 10) {
            break;
          }

          message.code = reader.string();
          continue;
        }
        case 2: {
          if (tag !== 18) {
            break;
          }

          message.message = reader.string();
          continue;
        }
        case 3: {
          if (tag !== 24) {
            break;
          }

          message.retriable = reader.bool();
          continue;
        }
      }
      if ((tag & 7) === 4 || tag === 0) {
        break;
      }
      reader.skip(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): ErrorEvent {
    return {
      code: isSet(object.code) ? globalThis.String(object.code) : "",
      message: isSet(object.message) ? globalThis.String(object.message) : "",
      retriable: isSet(object.retriable) ? globalThis.Boolean(object.retriable) : false,
    };
  },

  toJSON(message: ErrorEvent): unknown {
    const obj: any = {};
    if (message.code !== "") {
      obj.code = message.code;
    }
    if (message.message !== "") {
      obj.message = message.message;
    }
    if (message.retriable !== false) {
      obj.retriable = message.retriable;
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<ErrorEvent>, I>>(base?: I): ErrorEvent {
    return ErrorEvent.fromPartial(base ?? ({} as any));
  },
  fromPartial<I extends Exact<DeepPartial<ErrorEvent>, I>>(object: I): ErrorEvent {
    const message = createBaseErrorEvent();
    message.code = object.code ?? "";
    message.message = object.message ?? "";
    message.retriable = object.retriable ?? false;
    return message;
  },
};

function createBaseDoneStats(): DoneStats {
  return { tokensIn: 0, tokensOut: 0, chunksRetrieved: 0 };
}

export const DoneStats: MessageFns<DoneStats> = {
  encode(message: DoneStats, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
    if (message.tokensIn !== 0) {
      writer.uint32(8).int32(message.tokensIn);
    }
    if (message.tokensOut !== 0) {
      writer.uint32(16).int32(message.tokensOut);
    }
    if (message.chunksRetrieved !== 0) {
      writer.uint32(24).int32(message.chunksRetrieved);
    }
    return writer;
  },

  decode(input: BinaryReader | Uint8Array, length?: number): DoneStats {
    const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
    const end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseDoneStats();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1: {
          if (tag !== 8) {
            break;
          }

          message.tokensIn = reader.int32();
          continue;
        }
        case 2: {
          if (tag !== 16) {
            break;
          }

          message.tokensOut = reader.int32();
          continue;
        }
        case 3: {
          if (tag !== 24) {
            break;
          }

          message.chunksRetrieved = reader.int32();
          continue;
        }
      }
      if ((tag & 7) === 4 || tag === 0) {
        break;
      }
      reader.skip(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): DoneStats {
    return {
      tokensIn: isSet(object.tokensIn)
        ? globalThis.Number(object.tokensIn)
        : isSet(object.tokens_in)
        ? globalThis.Number(object.tokens_in)
        : 0,
      tokensOut: isSet(object.tokensOut)
        ? globalThis.Number(object.tokensOut)
        : isSet(object.tokens_out)
        ? globalThis.Number(object.tokens_out)
        : 0,
      chunksRetrieved: isSet(object.chunksRetrieved)
        ? globalThis.Number(object.chunksRetrieved)
        : isSet(object.chunks_retrieved)
        ? globalThis.Number(object.chunks_retrieved)
        : 0,
    };
  },

  toJSON(message: DoneStats): unknown {
    const obj: any = {};
    if (message.tokensIn !== 0) {
      obj.tokensIn = Math.round(message.tokensIn);
    }
    if (message.tokensOut !== 0) {
      obj.tokensOut = Math.round(message.tokensOut);
    }
    if (message.chunksRetrieved !== 0) {
      obj.chunksRetrieved = Math.round(message.chunksRetrieved);
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<DoneStats>, I>>(base?: I): DoneStats {
    return DoneStats.fromPartial(base ?? ({} as any));
  },
  fromPartial<I extends Exact<DeepPartial<DoneStats>, I>>(object: I): DoneStats {
    const message = createBaseDoneStats();
    message.tokensIn = object.tokensIn ?? 0;
    message.tokensOut = object.tokensOut ?? 0;
    message.chunksRetrieved = object.chunksRetrieved ?? 0;
    return message;
  },
};

function createBaseDoneEvent(): DoneEvent {
  return { stats: undefined };
}

export const DoneEvent: MessageFns<DoneEvent> = {
  encode(message: DoneEvent, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
    if (message.stats !== undefined) {
      DoneStats.encode(message.stats, writer.uint32(10).fork()).join();
    }
    return writer;
  },

  decode(input: BinaryReader | Uint8Array, length?: number): DoneEvent {
    const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
    const end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseDoneEvent();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1: {
          if (tag !== 10) {
            break;
          }

          message.stats = DoneStats.decode(reader, reader.uint32());
          continue;
        }
      }
      if ((tag & 7) === 4 || tag === 0) {
        break;
      }
      reader.skip(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): DoneEvent {
    return { stats: isSet(object.stats) ? DoneStats.fromJSON(object.stats) : undefined };
  },

  toJSON(message: DoneEvent): unknown {
    const obj: any = {};
    if (message.stats !== undefined) {
      obj.stats = DoneStats.toJSON(message.stats);
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<DoneEvent>, I>>(base?: I): DoneEvent {
    return DoneEvent.fromPartial(base ?? ({} as any));
  },
  fromPartial<I extends Exact<DeepPartial<DoneEvent>, I>>(object: I): DoneEvent {
    const message = createBaseDoneEvent();
    message.stats = (object.stats !== undefined && object.stats !== null)
      ? DoneStats.fromPartial(object.stats)
      : undefined;
    return message;
  },
};

function createBaseChatEvent(): ChatEvent {
  return {
    token: undefined,
    citation: undefined,
    agentStep: undefined,
    toolCall: undefined,
    error: undefined,
    done: undefined,
  };
}

export const ChatEvent: MessageFns<ChatEvent> = {
  encode(message: ChatEvent, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
    if (message.token !== undefined) {
      TokenEvent.encode(message.token, writer.uint32(10).fork()).join();
    }
    if (message.citation !== undefined) {
      CitationEvent.encode(message.citation, writer.uint32(18).fork()).join();
    }
    if (message.agentStep !== undefined) {
      AgentStepEvent.encode(message.agentStep, writer.uint32(26).fork()).join();
    }
    if (message.toolCall !== undefined) {
      ToolCallEvent.encode(message.toolCall, writer.uint32(34).fork()).join();
    }
    if (message.error !== undefined) {
      ErrorEvent.encode(message.error, writer.uint32(42).fork()).join();
    }
    if (message.done !== undefined) {
      DoneEvent.encode(message.done, writer.uint32(50).fork()).join();
    }
    return writer;
  },

  decode(input: BinaryReader | Uint8Array, length?: number): ChatEvent {
    const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
    const end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseChatEvent();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1: {
          if (tag !== 10) {
            break;
          }

          message.token = TokenEvent.decode(reader, reader.uint32());
          continue;
        }
        case 2: {
          if (tag !== 18) {
            break;
          }

          message.citation = CitationEvent.decode(reader, reader.uint32());
          continue;
        }
        case 3: {
          if (tag !== 26) {
            break;
          }

          message.agentStep = AgentStepEvent.decode(reader, reader.uint32());
          continue;
        }
        case 4: {
          if (tag !== 34) {
            break;
          }

          message.toolCall = ToolCallEvent.decode(reader, reader.uint32());
          continue;
        }
        case 5: {
          if (tag !== 42) {
            break;
          }

          message.error = ErrorEvent.decode(reader, reader.uint32());
          continue;
        }
        case 6: {
          if (tag !== 50) {
            break;
          }

          message.done = DoneEvent.decode(reader, reader.uint32());
          continue;
        }
      }
      if ((tag & 7) === 4 || tag === 0) {
        break;
      }
      reader.skip(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): ChatEvent {
    return {
      token: isSet(object.token) ? TokenEvent.fromJSON(object.token) : undefined,
      citation: isSet(object.citation) ? CitationEvent.fromJSON(object.citation) : undefined,
      agentStep: isSet(object.agentStep)
        ? AgentStepEvent.fromJSON(object.agentStep)
        : isSet(object.agent_step)
        ? AgentStepEvent.fromJSON(object.agent_step)
        : undefined,
      toolCall: isSet(object.toolCall)
        ? ToolCallEvent.fromJSON(object.toolCall)
        : isSet(object.tool_call)
        ? ToolCallEvent.fromJSON(object.tool_call)
        : undefined,
      error: isSet(object.error) ? ErrorEvent.fromJSON(object.error) : undefined,
      done: isSet(object.done) ? DoneEvent.fromJSON(object.done) : undefined,
    };
  },

  toJSON(message: ChatEvent): unknown {
    const obj: any = {};
    if (message.token !== undefined) {
      obj.token = TokenEvent.toJSON(message.token);
    }
    if (message.citation !== undefined) {
      obj.citation = CitationEvent.toJSON(message.citation);
    }
    if (message.agentStep !== undefined) {
      obj.agentStep = AgentStepEvent.toJSON(message.agentStep);
    }
    if (message.toolCall !== undefined) {
      obj.toolCall = ToolCallEvent.toJSON(message.toolCall);
    }
    if (message.error !== undefined) {
      obj.error = ErrorEvent.toJSON(message.error);
    }
    if (message.done !== undefined) {
      obj.done = DoneEvent.toJSON(message.done);
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<ChatEvent>, I>>(base?: I): ChatEvent {
    return ChatEvent.fromPartial(base ?? ({} as any));
  },
  fromPartial<I extends Exact<DeepPartial<ChatEvent>, I>>(object: I): ChatEvent {
    const message = createBaseChatEvent();
    message.token = (object.token !== undefined && object.token !== null)
      ? TokenEvent.fromPartial(object.token)
      : undefined;
    message.citation = (object.citation !== undefined && object.citation !== null)
      ? CitationEvent.fromPartial(object.citation)
      : undefined;
    message.agentStep = (object.agentStep !== undefined && object.agentStep !== null)
      ? AgentStepEvent.fromPartial(object.agentStep)
      : undefined;
    message.toolCall = (object.toolCall !== undefined && object.toolCall !== null)
      ? ToolCallEvent.fromPartial(object.toolCall)
      : undefined;
    message.error = (object.error !== undefined && object.error !== null)
      ? ErrorEvent.fromPartial(object.error)
      : undefined;
    message.done = (object.done !== undefined && object.done !== null) ? DoneEvent.fromPartial(object.done) : undefined;
    return message;
  },
};

/**
 * Streaming chat. Server returns a stream of ChatEvent; one event per
 * model delta, citation, agent step, tool-call request, error, or done.
 * Conversation state is NOT persisted — the caller sends the full
 * message history every call. `conversation_id` exists only for audit
 * correlation.
 */
export type ChatServiceService = typeof ChatServiceService;
export const ChatServiceService = {
  chat: {
    path: "/apf.ai.v1.ChatService/Chat" as const,
    requestStream: false as const,
    responseStream: true as const,
    requestSerialize: (value: ChatRequest): Buffer => Buffer.from(ChatRequest.encode(value).finish()),
    requestDeserialize: (value: Buffer): ChatRequest => ChatRequest.decode(value),
    responseSerialize: (value: ChatEvent): Buffer => Buffer.from(ChatEvent.encode(value).finish()),
    responseDeserialize: (value: Buffer): ChatEvent => ChatEvent.decode(value),
  },
} as const;

export interface ChatServiceServer extends UntypedServiceImplementation {
  chat: handleServerStreamingCall<ChatRequest, ChatEvent>;
}

export interface ChatServiceClient extends Client {
  chat(request: ChatRequest, options?: Partial<CallOptions>): ClientReadableStream<ChatEvent>;
  chat(request: ChatRequest, metadata?: Metadata, options?: Partial<CallOptions>): ClientReadableStream<ChatEvent>;
}

export const ChatServiceClient = makeGenericClientConstructor(
  ChatServiceService,
  "apf.ai.v1.ChatService",
) as unknown as {
  new (address: string, credentials: ChannelCredentials, options?: Partial<ClientOptions>): ChatServiceClient;
  service: typeof ChatServiceService;
  serviceName: string;
};

type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;

type DeepPartial<T> = T extends Builtin ? T
  : T extends Long ? string | number | Long : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>>
  : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
  : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
  : Partial<T>;

type KeysOfUnion<T> = T extends T ? keyof T : never;
type Exact<P, I extends P> = P extends Builtin ? P
  : P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };

function isObject(value: any): boolean {
  return typeof value === "object" && value !== null;
}

function isSet(value: any): boolean {
  return value !== null && value !== undefined;
}

interface MessageFns<T> {
  encode(message: T, writer?: BinaryWriter): BinaryWriter;
  decode(input: BinaryReader | Uint8Array, length?: number): T;
  fromJSON(object: any): T;
  toJSON(message: T): unknown;
  create<I extends Exact<DeepPartial<T>, I>>(base?: I): T;
  fromPartial<I extends Exact<DeepPartial<T>, I>>(object: I): T;
}
