feat: display inference statistics in chat UI

Add InferenceStats proto message and InferenceStatsPanel component that
displays token counts, throughput, and context window utilization as a
collapsible panel below assistant messages after orchestration completes.

Closes #43

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
shahondin1624
2026-03-13 14:44:12 +01:00
parent e93158f670
commit 52eaf661c4
7 changed files with 223 additions and 5 deletions

View File

@@ -12,7 +12,7 @@ import type { Message } from "@bufbuild/protobuf";
* Describes the file llm_multiverse/v1/common.proto.
*/
export const file_llm_multiverse_v1_common: GenFile = /*@__PURE__*/
fileDesc("Ch5sbG1fbXVsdGl2ZXJzZS92MS9jb21tb24ucHJvdG8SEWxsbV9tdWx0aXZlcnNlLnYxItABCghBcnRpZmFjdBINCgVsYWJlbBgBIAEoCRIPCgdjb250ZW50GAIgASgJEjYKDWFydGlmYWN0X3R5cGUYAyABKA4yHy5sbG1fbXVsdGl2ZXJzZS52MS5BcnRpZmFjdFR5cGUSOwoIbWV0YWRhdGEYBCADKAsyKS5sbG1fbXVsdGl2ZXJzZS52MS5BcnRpZmFjdC5NZXRhZGF0YUVudHJ5Gi8KDU1ldGFkYXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJqCg9BZ2VudElkZW50aWZpZXISEAoIYWdlbnRfaWQYASABKAkSMAoKYWdlbnRfdHlwZRgCIAEoDjIcLmxsbV9tdWx0aXZlcnNlLnYxLkFnZW50VHlwZRITCgtzcGF3bl9kZXB0aBgDIAEoDSJCCgxBZ2VudExpbmVhZ2USMgoGYWdlbnRzGAEgAygLMiIubGxtX211bHRpdmVyc2UudjEuQWdlbnRJZGVudGlmaWVyItcBCg5TZXNzaW9uQ29udGV4dBISCgpzZXNzaW9uX2lkGAEgASgJEg8KB3VzZXJfaWQYAiABKAkSNgoNYWdlbnRfbGluZWFnZRgDIAEoCzIfLmxsbV9tdWx0aXZlcnNlLnYxLkFnZW50TGluZWFnZRI4Cg5vdmVycmlkZV9sZXZlbBgEIAEoDjIgLmxsbV9tdWx0aXZlcnNlLnYxLk92ZXJyaWRlTGV2ZWwSLgoKY3JlYXRlZF9hdBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXAinQEKC0Vycm9yRGV0YWlsEgwKBGNvZGUYASABKAkSDwoHbWVzc2FnZRgCIAEoCRI+CghtZXRhZGF0YRgDIAMoCzIsLmxsbV9tdWx0aXZlcnNlLnYxLkVycm9yRGV0YWlsLk1ldGFkYXRhRW50cnkaLwoNTWV0YWRhdGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBImcKD01lbW9yeUNhbmRpZGF0ZRIPCgdjb250ZW50GAEgASgJEi8KBnNvdXJjZRgCIAEoDjIfLmxsbV9tdWx0aXZlcnNlLnYxLlJlc3VsdFNvdXJjZRISCgpjb25maWRlbmNlGAMgASgCIuACCg5TdWJhZ2VudFJlc3VsdBIvCgZzdGF0dXMYASABKA4yHy5sbG1fbXVsdGl2ZXJzZS52MS5SZXN1bHRTdGF0dXMSDwoHc3VtbWFyeRgCIAEoCRIuCglhcnRpZmFjdHMYAyADKAsyGy5sbG1fbXVsdGl2ZXJzZS52MS5BcnRpZmFjdBI4Cg5yZXN1bHRfcXVhbGl0eRgEIAEoDjIgLmxsbV9tdWx0aXZlcnNlLnYxLlJlc3VsdFF1YWxpdHkSLwoGc291cmNlGAUgASgOMh8ubGxtX211bHRpdmVyc2UudjEuUmVzdWx0U291cmNlEkEKFW5ld19tZW1vcnlfY2FuZGlkYXRlcxgGIAMoCzIiLmxsbV9tdWx0aXZlcnNlLnYxLk1lbW9yeUNhbmRpZGF0ZRIbCg5mYWlsdXJlX3JlYXNvbhgHIAEoCUgAiAEBQhEKD19mYWlsdXJlX3JlYXNvbiqoAQoJQWdlbnRUeXBlEhoKFkFHRU5UX1RZUEVfVU5TUEVDSUZJRUQQABIbChdBR0VOVF9UWVBFX09SQ0hFU1RSQVRPUhABEhkKFUFHRU5UX1RZUEVfUkVTRUFSQ0hFUhACEhQKEEFHRU5UX1RZUEVfQ09ERVIQAxIXChNBR0VOVF9UWVBFX1NZU0FETUlOEAQSGAoUQUdFTlRfVFlQRV9BU1NJU1RBTlQQBSr1AQoIVG9vbFR5cGUSGQoVVE9PTF9UWVBFX1VOU1BFQ0lGSUVEEAASGQoVVE9PTF9UWVBFX01FTU9SWV9SRUFEEAESGgoWVE9PTF9UWVBFX01FTU9SWV9XUklURRACEhgKFFRPT0xfVFlQRV9XRUJfU0VBUkNIEAMSFQoRVE9PTF9UWVBFX0ZTX1JFQUQQBBIWChJUT09MX1RZUEVfRlNfV1JJVEUQBRIWChJUT09MX1RZUEVfUlVOX0NPREUQBhIXChNUT09MX1RZUEVfUlVOX1NIRUxMEAcSHQoZVE9PTF9UWVBFX1BBQ0tBR0VfSU5TVEFMTBAIKnoKDU92ZXJyaWRlTGV2ZWwSHgoaT1ZFUlJJREVfTEVWRUxfVU5TUEVDSUZJRUQQABIXChNPVkVSUklERV9MRVZFTF9OT05FEAESGAoUT1ZFUlJJREVfTEVWRUxfUkVMQVgQAhIWChJPVkVSUklERV9MRVZFTF9BTEwQAyp9CgxSZXN1bHRTdGF0dXMSHQoZUkVTVUxUX1NUQVRVU19VTlNQRUNJRklFRBAAEhkKFVJFU1VMVF9TVEFUVVNfU1VDQ0VTUxABEhkKFVJFU1VMVF9TVEFUVVNfUEFSVElBTBACEhgKFFJFU1VMVF9TVEFUVVNfRkFJTEVEEAMqhwEKDVJlc3VsdFF1YWxpdHkSHgoaUkVTVUxUX1FVQUxJVFlfVU5TUEVDSUZJRUQQABIbChdSRVNVTFRfUVVBTElUWV9WRVJJRklFRBABEhsKF1JFU1VMVF9RVUFMSVRZX0lORkVSUkVEEAISHAoYUkVTVUxUX1FVQUxJVFlfVU5DRVJUQUlOEAMqhgEKDFJlc3VsdFNvdXJjZRIdChlSRVNVTFRfU09VUkNFX1VOU1BFQ0lGSUVEEAASHQoZUkVTVUxUX1NPVVJDRV9UT09MX09VVFBVVBABEiEKHVJFU1VMVF9TT1VSQ0VfTU9ERUxfS05PV0xFREdFEAISFQoRUkVTVUxUX1NPVVJDRV9XRUIQAyqgAQoMQXJ0aWZhY3RUeXBlEh0KGUFSVElGQUNUX1RZUEVfVU5TUEVDSUZJRUQQABIWChJBUlRJRkFDVF9UWVBFX0NPREUQARIWChJBUlRJRkFDVF9UWVBFX1RFWFQQAhIgChxBUlRJRkFDVF9UWVBFX0NPTU1BTkRfT1VUUFVUEAMSHwobQVJUSUZBQ1RfVFlQRV9TRUFSQ0hfUkVTVUxUEARiBnByb3RvMw", [file_google_protobuf_timestamp]);
fileDesc("Ch5sbG1fbXVsdGl2ZXJzZS92MS9jb21tb24ucHJvdG8SEWxsbV9tdWx0aXZlcnNlLnYxItABCghBcnRpZmFjdBINCgVsYWJlbBgBIAEoCRIPCgdjb250ZW50GAIgASgJEjYKDWFydGlmYWN0X3R5cGUYAyABKA4yHy5sbG1fbXVsdGl2ZXJzZS52MS5BcnRpZmFjdFR5cGUSOwoIbWV0YWRhdGEYBCADKAsyKS5sbG1fbXVsdGl2ZXJzZS52MS5BcnRpZmFjdC5NZXRhZGF0YUVudHJ5Gi8KDU1ldGFkYXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJqCg9BZ2VudElkZW50aWZpZXISEAoIYWdlbnRfaWQYASABKAkSMAoKYWdlbnRfdHlwZRgCIAEoDjIcLmxsbV9tdWx0aXZlcnNlLnYxLkFnZW50VHlwZRITCgtzcGF3bl9kZXB0aBgDIAEoDSJCCgxBZ2VudExpbmVhZ2USMgoGYWdlbnRzGAEgAygLMiIubGxtX211bHRpdmVyc2UudjEuQWdlbnRJZGVudGlmaWVyItcBCg5TZXNzaW9uQ29udGV4dBISCgpzZXNzaW9uX2lkGAEgASgJEg8KB3VzZXJfaWQYAiABKAkSNgoNYWdlbnRfbGluZWFnZRgDIAEoCzIfLmxsbV9tdWx0aXZlcnNlLnYxLkFnZW50TGluZWFnZRI4Cg5vdmVycmlkZV9sZXZlbBgEIAEoDjIgLmxsbV9tdWx0aXZlcnNlLnYxLk92ZXJyaWRlTGV2ZWwSLgoKY3JlYXRlZF9hdBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXAinQEKC0Vycm9yRGV0YWlsEgwKBGNvZGUYASABKAkSDwoHbWVzc2FnZRgCIAEoCRI+CghtZXRhZGF0YRgDIAMoCzIsLmxsbV9tdWx0aXZlcnNlLnYxLkVycm9yRGV0YWlsLk1ldGFkYXRhRW50cnkaLwoNTWV0YWRhdGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBImcKD01lbW9yeUNhbmRpZGF0ZRIPCgdjb250ZW50GAEgASgJEi8KBnNvdXJjZRgCIAEoDjIfLmxsbV9tdWx0aXZlcnNlLnYxLlJlc3VsdFNvdXJjZRISCgpjb25maWRlbmNlGAMgASgCIpABCg5JbmZlcmVuY2VTdGF0cxIVCg1wcm9tcHRfdG9rZW5zGAEgASgNEhkKEWNvbXBsZXRpb25fdG9rZW5zGAIgASgNEhQKDHRvdGFsX3Rva2VucxgDIAEoDRIbChNjb250ZXh0X3dpbmRvd19zaXplGAQgASgNEhkKEXRva2Vuc19wZXJfc2Vjb25kGAUgASgCIuACCg5TdWJhZ2VudFJlc3VsdBIvCgZzdGF0dXMYASABKA4yHy5sbG1fbXVsdGl2ZXJzZS52MS5SZXN1bHRTdGF0dXMSDwoHc3VtbWFyeRgCIAEoCRIuCglhcnRpZmFjdHMYAyADKAsyGy5sbG1fbXVsdGl2ZXJzZS52MS5BcnRpZmFjdBI4Cg5yZXN1bHRfcXVhbGl0eRgEIAEoDjIgLmxsbV9tdWx0aXZlcnNlLnYxLlJlc3VsdFF1YWxpdHkSLwoGc291cmNlGAUgASgOMh8ubGxtX211bHRpdmVyc2UudjEuUmVzdWx0U291cmNlEkEKFW5ld19tZW1vcnlfY2FuZGlkYXRlcxgGIAMoCzIiLmxsbV9tdWx0aXZlcnNlLnYxLk1lbW9yeUNhbmRpZGF0ZRIbCg5mYWlsdXJlX3JlYXNvbhgHIAEoCUgAiAEBQhEKD19mYWlsdXJlX3JlYXNvbiqoAQoJQWdlbnRUeXBlEhoKFkFHRU5UX1RZUEVfVU5TUEVDSUZJRUQQABIbChdBR0VOVF9UWVBFX09SQ0hFU1RSQVRPUhABEhkKFUFHRU5UX1RZUEVfUkVTRUFSQ0hFUhACEhQKEEFHRU5UX1RZUEVfQ09ERVIQAxIXChNBR0VOVF9UWVBFX1NZU0FETUlOEAQSGAoUQUdFTlRfVFlQRV9BU1NJU1RBTlQQBSr1AQoIVG9vbFR5cGUSGQoVVE9PTF9UWVBFX1VOU1BFQ0lGSUVEEAASGQoVVE9PTF9UWVBFX01FTU9SWV9SRUFEEAESGgoWVE9PTF9UWVBFX01FTU9SWV9XUklURRACEhgKFFRPT0xfVFlQRV9XRUJfU0VBUkNIEAMSFQoRVE9PTF9UWVBFX0ZTX1JFQUQQBBIWChJUT09MX1RZUEVfRlNfV1JJVEUQBRIWChJUT09MX1RZUEVfUlVOX0NPREUQBhIXChNUT09MX1RZUEVfUlVOX1NIRUxMEAcSHQoZVE9PTF9UWVBFX1BBQ0tBR0VfSU5TVEFMTBAIKnoKDU92ZXJyaWRlTGV2ZWwSHgoaT1ZFUlJJREVfTEVWRUxfVU5TUEVDSUZJRUQQABIXChNPVkVSUklERV9MRVZFTF9OT05FEAESGAoUT1ZFUlJJREVfTEVWRUxfUkVMQVgQAhIWChJPVkVSUklERV9MRVZFTF9BTEwQAyp9CgxSZXN1bHRTdGF0dXMSHQoZUkVTVUxUX1NUQVRVU19VTlNQRUNJRklFRBAAEhkKFVJFU1VMVF9TVEFUVVNfU1VDQ0VTUxABEhkKFVJFU1VMVF9TVEFUVVNfUEFSVElBTBACEhgKFFJFU1VMVF9TVEFUVVNfRkFJTEVEEAMqhwEKDVJlc3VsdFF1YWxpdHkSHgoaUkVTVUxUX1FVQUxJVFlfVU5TUEVDSUZJRUQQABIbChdSRVNVTFRfUVVBTElUWV9WRVJJRklFRBABEhsKF1JFU1VMVF9RVUFMSVRZX0lORkVSUkVEEAISHAoYUkVTVUxUX1FVQUxJVFlfVU5DRVJUQUlOEAMqhgEKDFJlc3VsdFNvdXJjZRIdChlSRVNVTFRfU09VUkNFX1VOU1BFQ0lGSUVEEAASHQoZUkVTVUxUX1NPVVJDRV9UT09MX09VVFBVVBABEiEKHVJFU1VMVF9TT1VSQ0VfTU9ERUxfS05PV0xFREdFEAISFQoRUkVTVUxUX1NPVVJDRV9XRUIQAyqgAQoMQXJ0aWZhY3RUeXBlEh0KGUFSVElGQUNUX1RZUEVfVU5TUEVDSUZJRUQQABIWChJBUlRJRkFDVF9UWVBFX0NPREUQARIWChJBUlRJRkFDVF9UWVBFX1RFWFQQAhIgChxBUlRJRkFDVF9UWVBFX0NPTU1BTkRfT1VUUFVUEAMSHwobQVJUSUZBQ1RfVFlQRV9TRUFSQ0hfUkVTVUxUEARiBnByb3RvMw", [file_google_protobuf_timestamp]);
/**
* A concrete output produced by an agent (code, command output, etc.).
@@ -200,6 +200,55 @@ export type MemoryCandidate = Message<"llm_multiverse.v1.MemoryCandidate"> & {
export const MemoryCandidateSchema: GenMessage<MemoryCandidate> = /*@__PURE__*/
messageDesc(file_llm_multiverse_v1_common, 5);
/**
* Inference statistics surfaced from model-gateway through the orchestrator.
*
* @generated from message llm_multiverse.v1.InferenceStats
*/
export type InferenceStats = Message<"llm_multiverse.v1.InferenceStats"> & {
/**
* Number of tokens in the prompt.
*
* @generated from field: uint32 prompt_tokens = 1;
*/
promptTokens: number;
/**
* Number of tokens generated.
*
* @generated from field: uint32 completion_tokens = 2;
*/
completionTokens: number;
/**
* Sum of prompt + completion tokens.
*
* @generated from field: uint32 total_tokens = 3;
*/
totalTokens: number;
/**
* Model's maximum context length.
*
* @generated from field: uint32 context_window_size = 4;
*/
contextWindowSize: number;
/**
* Generation throughput (tokens per second).
*
* @generated from field: float tokens_per_second = 5;
*/
tokensPerSecond: number;
};
/**
* Describes the message llm_multiverse.v1.InferenceStats.
* Use `create(InferenceStatsSchema)` to create a new message.
*/
export const InferenceStatsSchema: GenMessage<InferenceStats> = /*@__PURE__*/
messageDesc(file_llm_multiverse_v1_common, 6);
/**
* Standardized return value from any subagent to its parent.
*
@@ -251,7 +300,7 @@ export type SubagentResult = Message<"llm_multiverse.v1.SubagentResult"> & {
* Use `create(SubagentResultSchema)` to create a new message.
*/
export const SubagentResultSchema: GenMessage<SubagentResult> = /*@__PURE__*/
messageDesc(file_llm_multiverse_v1_common, 6);
messageDesc(file_llm_multiverse_v1_common, 7);
/**
* Agent types with distinct tool permission manifests.