-
Notifications
You must be signed in to change notification settings - Fork 16
Add docs/GENERATOR_METADATA.md GetCascadeTrajectoryGeneratorMetadata RPC for context token usage #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Zen0-99
wants to merge
2
commits into
rsvedant:master
Choose a base branch
from
Zen0-99:add-generator-metadata
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Add docs/GENERATOR_METADATA.md GetCascadeTrajectoryGeneratorMetadata RPC for context token usage #17
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,222 @@ | ||
| # Cascade Context Token Usage — `GetCascadeTrajectoryGeneratorMetadata` | ||
|
|
||
| This document covers a separate RPC that the existing | ||
| [CASCADE_PROTOCOL.md](CASCADE_PROTOCOL.md) and | ||
| [API spec](WINDSURF_API_SPEC.md) don't mention: | ||
| **`GetCascadeTrajectoryGeneratorMetadata`**. This is the endpoint the IDE | ||
| uses to populate the context-usage indicator (e.g. `63% (125K / 200K)`) | ||
| shown next to the Cascade chat input. | ||
|
|
||
| If you need real token counts — not a character-based estimate — this is | ||
| where they live. | ||
|
|
||
| --- | ||
|
|
||
| ## 1. It's a separate RPC, not part of `GetCascadeTrajectorySteps` | ||
|
|
||
| `GetCascadeTrajectorySteps` returns the trajectory *content* (planner | ||
| responses, tool calls, thinking). It does **not** include token usage. | ||
|
|
||
| Token usage lives in a parallel metadata stream that you poll alongside | ||
| the trajectory steps: | ||
|
|
||
| ```text | ||
| InitializeCascadePanelState(metadata) | ||
| → StartCascade(metadata, source) → cascade_id | ||
| → SendUserCascadeMessage(cascade_id, …) | ||
| → poll GetCascadeTrajectorySteps(cascade_id, step_offset) ← content | ||
| → poll GetCascadeTrajectoryGeneratorMetadata(cascade_id, offset) ← token counts | ||
| ``` | ||
|
|
||
| Both endpoints use offset-based pagination. Track the offsets independently | ||
| per cascade session. | ||
|
|
||
| --- | ||
|
|
||
| ## 2. Request format | ||
|
|
||
| ```protobuf | ||
| GetCascadeTrajectoryGeneratorMetadataRequest: | ||
| field 1: cascade_id (string) | ||
| field 2: generator_metadata_offset (uint32) | ||
| ``` | ||
|
|
||
| Same `cascade_id` you get from `StartCascade`. The offset starts at 0 and | ||
| advances by the number of metadata entries returned each poll. | ||
|
|
||
| --- | ||
|
|
||
| ## 3. Response format | ||
|
|
||
| ```protobuf | ||
| GetCascadeTrajectoryGeneratorMetadataResponse: | ||
| field 1: generator_metadata (repeated CortexStepGeneratorMetadata) | ||
| ``` | ||
|
|
||
| Each `CortexStepGeneratorMetadata` entry corresponds to one LLM invocation | ||
| within the turn. A single user message can produce multiple entries (e.g. | ||
| if the planner makes multiple LLM calls for tool selection + response | ||
| generation). | ||
|
|
||
| --- | ||
|
|
||
| ## 4. The token-usage chain | ||
|
|
||
| ```text | ||
| CortexStepGeneratorMetadata | ||
| └─ field 1: chat_model (oneof "metadata", ChatModelMetadata) | ||
| └─ field 4: usage (ModelUsageStats) | ||
| ├─ field 2: input_tokens (uint64) ← context tokens used | ||
| ├─ field 3: output_tokens (uint64) ← tokens generated | ||
| ├─ field 4: cache_write_tokens (uint64) | ||
| ├─ field 5: cache_read_tokens (uint64) | ||
| ├─ field 6: api_provider (enum) | ||
| ├─ field 7: message_id (string) | ||
| ├─ field 8: response_header (map<string, int64>) | ||
| ├─ field 9: model_uid (string) | ||
| ├─ field 10: billing_model_uid (string) | ||
| └─ field 11: requested_model_uid (string) | ||
| ``` | ||
|
|
||
| **`ModelUsageStats.input_tokens` (field 2) is the value the IDE displays | ||
| as the numerator in its context-usage indicator.** It represents the total | ||
| prompt tokens sent to the LLM for that invocation — system prompt + | ||
| conversation history + tool results + the current user message. | ||
|
|
||
| The **last** entry with `input_tokens > 0` in a poll response represents | ||
| the most recent context usage. Use it for the live meter. | ||
|
|
||
| --- | ||
|
|
||
| ## 5. `CortexStepGeneratorMetadata` full schema | ||
|
|
||
| | Field | Name | Type | Notes | | ||
| |-------|---------------------------------------|-----------|------------------------------------| | ||
| | 1 | chat_model | message | oneof "metadata" → ChatModelMetadata | | ||
| | 2 | step_indices | uint32[] | Which steps this metadata covers | | ||
| | 3 | planner_config | message | Planner configuration | | ||
| | 4 | execution_id | string | | | ||
| | 5 | error | string | | | ||
| | 6 | parallel_rollout_generator_metadata | message | | | ||
| | 7 | arena_cap_reached | bool | | | ||
|
|
||
| --- | ||
|
|
||
| ## 6. `ChatModelMetadata` full schema | ||
|
|
||
| | Field | Name | Type | Notes | | ||
| |-------|---------------------------|-----------|------------------------------------| | ||
| | 1 | system_prompt | string | | | ||
| | 2 | message_prompts | message[] | ChatMessagePrompt (repeated) | | ||
| | 3 | model (deprecated) | enum | Model enum | | ||
| | 4 | usage | message | **ModelUsageStats** ← token counts | | ||
| | 5 | model_cost | double | | | ||
| | 6 | last_cache_index | uint32 | | | ||
| | 7 | tool_choice | message | | | ||
| | 8 | tools | message[] | ChatToolDefinition (repeated) | | ||
| | 9 | chat_start_metadata | message | | | ||
| | 10 | message_metadata | message[] | MessagePromptMetadata | | ||
| | 11 | time_to_first_token | Duration | | | ||
| | 12 | streaming_duration | Duration | | | ||
| | 13 | credit_cost | int32 | | | ||
| | 14 | retries | uint32 | | | ||
| | 15 | model_uid | string | | | ||
| | 16 | acu_cost | double | | | ||
| | 18 | quota_cost_basis_points | sint32 | optional | | ||
| | 19 | overage_cost_cents | sint32 | optional | | ||
| | 20 | response_dimension_groups | message[] | | | ||
|
|
||
| --- | ||
|
|
||
| ## 7. Where the denominator (max context window) comes from | ||
|
|
||
| The percentage denominator is **not** in the generator metadata. It comes | ||
| from `IntentToolConfig`: | ||
|
|
||
| ```protobuf | ||
| exa.cortex_pb.IntentToolConfig: | ||
| field 1: intent_model (deprecated) (enum) | ||
| field 2: max_context_tokens (uint32) ← max context window | ||
| field 3: intent_model_uid (string) | ||
| ``` | ||
|
|
||
| This is per-model, not per-turn. To compute the percentage shown in the UI: | ||
|
|
||
| ```text | ||
| percentage = input_tokens / max_context_tokens * 100 | ||
| ``` | ||
|
|
||
| You can discover `max_context_tokens` for each model at runtime via | ||
| `GetCascadeModelConfigs` → `client_model_configs[].max_tokens`, | ||
| as noted in [CASCADE_PROTOCOL.md](CASCADE_PROTOCOL.md) §3. | ||
|
|
||
| --- | ||
|
|
||
| ## 8. Protocol notes | ||
|
|
||
| The existing docs describe `application/grpc-web+proto` framing. This | ||
| endpoint also works with **Buf Connect-RPC** (`application/proto`, | ||
| `Connect-Protocol-Version: 1`), which is simpler — no gRPC framing | ||
| (length-prefixed messages + trailers), just raw protobuf in the request | ||
| and response body. The IDE's bundled extension uses Protobuf-ES | ||
| (`@bufbuild/protobuf`), and the language server accepts both framing | ||
| styles. | ||
|
|
||
| Headers required (same as other Cascade RPCs): | ||
|
|
||
| ```http | ||
| Content-Type: application/proto | ||
| Connect-Protocol-Version: 1 | ||
| x-codeium-csrf-token: {csrf_token} | ||
| Authorization: Bearer {api_key} | ||
| ``` | ||
|
|
||
| URL pattern: | ||
|
|
||
| ```text | ||
| POST http://127.0.0.1:{port}/exa.language_server_pb.LanguageServerService/GetCascadeTrajectoryGeneratorMetadata | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 9. Verification | ||
|
|
||
| A test message ("Hello, what is 2+2?") with an injected system prompt | ||
| returned: | ||
|
|
||
| ```text | ||
| GeneratorMetadata #1: input_tokens=1719 output_tokens=25 | ||
| ``` | ||
|
|
||
| 1,719 input tokens for a trivial question is consistent with the system | ||
| prompt + context overhead that gets prepended before the user message | ||
| reaches the LLM. | ||
|
|
||
| --- | ||
|
|
||
| ## 10. How to discover this in `extension.js` | ||
|
|
||
| The bundled extension at `resources/app/extensions/windsurf/dist/extension.js` | ||
| uses Protobuf-ES, which registers every message type with a `static typeName` | ||
| and a `static fields` array. To find the schema: | ||
|
|
||
| ```bash | ||
| # List all protobuf type names | ||
| grep -oE 'typeName="exa\.[^"]+"' extension.js | sort -u | ||
|
|
||
| # Get field definitions for a specific type | ||
| # (search for the typeName, then read the newFieldList that follows) | ||
| ``` | ||
|
|
||
| The `ModelUsageStats` type is under `exa.codeium_common_pb`, not | ||
| `exa.cortex_pb` — it's shared between autocomplete and Cascade. The chain | ||
| from `CortexStepGeneratorMetadata` down to `ModelUsageStats` is: | ||
|
|
||
| ``` | ||
| exa.cortex_pb.CortexStepGeneratorMetadata | ||
| → exa.cortex_pb.ChatModelMetadata (field 1, oneof "metadata") | ||
| → exa.codeium_common_pb.ModelUsageStats (field 4, "usage") | ||
| ``` | ||
|
|
||
| Search for `input_tokens` or `ModelUsageStats` in the extension to find | ||
| the field definitions directly. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.