> ## Documentation Index
> Fetch the complete documentation index at: https://cadenya.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Get objective diagnostics

> Where an objective's context window is going, component by component. The endpoint to reach for when a run costs more than it should.

An agent that costs too much is almost always spending its window on something you did not expect: a tool set with three hundred tool definitions, a memory appendix nobody trimmed, a tool that returns a megabyte of JSON. This endpoint tells you which.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const { diagnostics } = await client.objectives.retrieveDiagnostics(objectiveId, { workspaceId });

  console.log(diagnostics.inputTokens);        // 1348
  console.log(diagnostics.contextLengths);
  // { systemPrompt: 159, toolDefinitions: 1246, userMessages: 31,
  //   assistantMessages: 258, toolResults: 935,
  //   skillsMemory: 0, episodicMemory: 0, availableTools: 0 }
  ```

  ```go Go theme={null}
  response, err := client.Objectives.GetDiagnostics(ctx, objectiveID,
  	cadenya.ObjectiveGetDiagnosticsParams{WorkspaceID: cadenya.String(workspaceID)})

  fmt.Println(response.Diagnostics.InputTokens) // 1348
  fmt.Printf("%+v\n", response.Diagnostics.ContextLengths)
  // {SystemPrompt:159 ToolDefinitions:1246 UserMessages:31
  //  AssistantMessages:258 ToolResults:935 ...}
  ```

  ```ruby Ruby theme={null}
  response = cadenya.objectives.retrieve_diagnostics(objective_id, workspace_id: workspace_id)

  puts response.diagnostics.input_tokens # 1348
  puts response.diagnostics.context_lengths
  ```

  ```bash cURL theme={null}
  curl "https://api.cadenya.com/v1/workspaces/${WORKSPACE_ID}/objectives/${OBJECTIVE_ID}/diagnostics" \
    -H "Authorization: Bearer ${CADENYA_API_KEY}"
  ```
</CodeGroup>

## Two different units, side by side

This is the thing to internalize before you build anything on this endpoint.

* **`contextLengths` values are character counts.** Every one of them.
* **`inputTokens` and `cachedInputTokens` are tokens.**

They sit on the same object with no unit in either name. An objective whose rendered system prompt is 41 characters long reports `systemPrompt: 41`, right next to `inputTokens: 660`.

<Warning>
  Do not sum `contextLengths` and compare it to `inputTokens`. One is characters, the other tokens. Use the components to see **proportions**, and use `inputTokens` for the absolute number.
</Warning>

Characters rather than tokens is a deliberate choice: it stores the raw measurement, so the token estimate can improve without rewriting history. Divide the total by `inputTokens` if you want your model's rough characters-per-token ratio.

## What each component is

| Field               | What lands there                                                                               |
| ------------------- | ---------------------------------------------------------------------------------------------- |
| `systemPrompt`      | The rendered `systemPromptTemplate`.                                                           |
| `toolDefinitions`   | Every tool's name, description, and JSON Schema.                                               |
| `availableTools`    | The discoverable-tools appendix, under [progressive discovery](/docs/guides/preventing-tool-bloat). |
| `skillsMemory`      | The manifest of your [skills layers](/docs/api-reference/memoryservice/create-a-new-memory-layer).  |
| `episodicMemory`    | The primer and table of what the agent has stored.                                             |
| `userMessages`      | Your turns.                                                                                    |
| `assistantMessages` | The agent's turns, including its reasoning.                                                    |
| `toolResults`       | What tools returned.                                                                           |

The interesting one is almost always `toolDefinitions`. In the sample above, before the agent had said a single word, tool definitions were **1,246 characters against a 159-character prompt**. Every objective pays that on every model call. That is what [tool filters](/docs/api-reference/toolservice/create-a-new-tool-set) and progressive discovery exist to shrink.

The second most interesting is `toolResults`, which is what [tool result clearing](/docs/api-reference/agentvariationservice/create-a-new-variation) reclaims during compaction.

## It only sees the current window

Diagnostics describe the objective's **live** context window, and they grow as it runs:

```
t+3s    inputTokens=0     sys=0    toolDefs=0     user=0   asst=0    toolResults=0
t+12s   inputTokens=832   sys=159  toolDefs=1246  user=31  asst=0    toolResults=0
t+25s   inputTokens=1348  sys=159  toolDefs=1246  user=31  asst=258  toolResults=935
```

Everything reads zero before the first model call, because nothing has been assembled yet.

<Warning>
  **A terminal objective returns all zeros.** `STATE_FINALIZED`, `STATE_FAILED`, `STATE_CANCELLED`, and `STATE_TIMED_OUT` all report `inputTokens: 0` and every component at `0`, even a run with sixty events behind it. The response is a `200`, so you cannot tell "no data retained" from "used no context."

  Read diagnostics while the objective is `STATE_PENDING`, `STATE_RUNNING`, or `STATE_WAITING`. For a post-mortem, [list its context windows](/docs/api-reference/objectiveservice/list-objective-context-windows) instead: those retain `promptTokens` and `completionTokens` per window, though not the component breakdown.
</Warning>

## Use it to find the fat

Grab a healthy objective mid-run and rank the components. The one at the top is where your money is.

```typescript theme={null}
const { diagnostics } = await client.objectives.retrieveDiagnostics(objectiveId, { workspaceId });
const total = Object.values(diagnostics.contextLengths).reduce((a, b) => a + b, 0);

for (const [component, chars] of Object.entries(diagnostics.contextLengths).sort((a, b) => b[1] - a[1])) {
  if (chars === 0) continue;
  console.log(component.padEnd(20), `${((100 * chars) / total).toFixed(1)}%`);
}
// toolDefinitions      47.4%
// toolResults          35.6%
// assistantMessages    9.8%
// systemPrompt         6.0%
// userMessages         1.2%
```

What to do with the answer:

* **`toolDefinitions` dominates.** Narrow the tool set with an include filter, or turn on progressive discovery so definitions load on demand.
* **`toolResults` dominates.** Enable `toolResultClearing` on the variation, or make the tool return less.
* **`skillsMemory` dominates.** Your manifest is too big. Split the layer, or tighten the entry descriptions.
* **`assistantMessages` dominates.** The agent is thinking in circles. That is a prompt problem, not a config one.

`cachedInputTokens` tells you how much of the window the provider served from its prompt cache. A high number is good: the stable head of your prompt (system prompt, tool definitions) is being reused across turns rather than re-billed.

## Related

<CardGroup cols={2}>
  <Card title="List context windows" icon="layer-group" href="/docs/api-reference/objectiveservice/list-objective-context-windows">
    Per-window token counts, retained after the objective ends.
  </Card>

  <Card title="Preventing tool bloat" icon="magnifying-glass" href="/docs/guides/preventing-tool-bloat">
    The fix when `toolDefinitions` is eating your window.
  </Card>

  <Card title="Create a variation" icon="code" href="/docs/api-reference/agentvariationservice/create-a-new-variation">
    Compaction, tool result clearing, and the trigger threshold.
  </Card>

  <Card title="Compaction" icon="compress" href="/docs/guides/objectives#context-windows">
    What happens when the window fills anyway.
  </Card>
</CardGroup>


## OpenAPI

````yaml get /v1/workspaces/{workspaceId}/objectives/{objectiveId}/diagnostics
openapi: 3.1.0
info:
  title: Cadenya API
  description: API for the Cadenya Agent Runtime platform.
  version: '1.0'
servers:
  - url: https://api.cadenya.com
    description: Production server
security:
  - bearerAuth: []
tags:
  - name: AIProviderKeyService
  - name: APIKeyService
    description: |-
      Issue, rotate, disable, and revoke a workspace's API keys. Every key
       belongs to exactly one workspace; the system-managed global account key is
       managed via GlobalAPIKeyService instead.
  - name: AccountService
    description: >-
      Manage the authenticated account. Accounts are the top-level
      organizational
       unit and contain one or more workspaces.
  - name: AgentScheduleService
    description: >-
      Manage recurring schedules attached to agents. Schedules trigger
      objectives
       on a cadence defined by AgentScheduleSpec.Schedule.
  - name: AgentService
    description: >-
      Manage AI agents within a workspace. Agents define AI behavior and tool
      access.
  - name: AgentVariationService
    description: >-
      Manage variations of an agent and their tool, sub-agent, and memory layer
      assignments.
  - name: GlobalAPIKeyService
    description: |-
      Manage the account's system-provisioned global API key. The global key is
       the only key that spans every workspace; it is created by the system and
       cannot be deleted, so the surface is retrieve, rotate, and the
       disable/enable kill switch.
  - name: MemoryService
    description: >-
      Manage memory layers and their entries. Layers are named containers that
      can
       be composed into an objective's memory cascade; entries are the keyed values
       within a layer. System-managed layers (e.g., episodic layers created by the
       runtime) cannot be mutated through this API.
  - name: ModelService
    description: |-
      Manage LLM models available to a workspace. Models represent provider and
       family pairs (e.g., "anthropic/claude-sonnet-4.6"). Workspaces are seeded
       with the supported models and you can enable or disable each one.
  - name: ObjectiveEventStreamsService
  - name: ObjectiveService
  - name: ProfilesService
    description: |-
      Operations on profiles, the account-level principals (users, API keys,
       system) that authenticate against the API.
  - name: SearchService
  - name: TenantService
    description: >-
      Read and erase tenants and the subjects under them. Tenants and subjects
      are
       created by assertion — on objective creation or widget session mint — never
       directly, so this service has no create or update: it exists to enumerate what
       assertions have produced, and to destroy it on request.
  - name: ToolService
    description: >-
      Manage tool sets and the tools they contain. Tool sets group related
      tools,
       and tools define specific capabilities available to agents.

       When a tool set is managed, only API key actors can modify its tools; human
       (profile) actors cannot.
  - name: UploadService
    description: |-
      Issue short-lived presigned URLs for direct client-to-object-storage
       uploads. Created uploads can be referenced by id when creating or updating
       resources that accept binary content (e.g., MemoryEntry).
  - name: WidgetService
    description: |-
      Manage embeddable chat widgets. A widget binds an agent to a globally
       unique hostname with a per-widget origin allowlist; browsers reach it with
       session tokens minted via WidgetSessionService.
  - name: WidgetSessionService
    description: >-
      Mint and manage widget sessions. Session creation is server-to-server
      only:
       the customer's backend authenticates its visitor, asserts tenant/subject
       context, attaches any per-visitor secrets, and receives a short-lived
       bearer token the browser uses against the widget host.
  - name: WorkspaceAdminService
    description: >-
      Administer workspaces across the account: create and archive workspaces
      and
       manage their membership. These operations are account-scoped and require the
       admin role (a token whose profile holds the WorkOS admin role); they live
       under /v1/account/workspaces rather than the workspace-scoped /v1/workspaces
       tree so an admin can manage any workspace in the account, including ones they
       are not themselves a member of.
  - name: WorkspaceSecretService
  - name: WorkspaceService
    description: |-
      Manage workspaces within an account. Workspaces provide organizational
       grouping and isolation for resources such as agents, tools, and API keys.

       This is the workspace-scoped, end-user surface. Administrative operations
       (create / archive workspaces, manage members) live in WorkspaceAdminService
       under /v1/account/workspaces and require the admin role.
paths:
  /v1/workspaces/{workspaceId}/objectives/{objectiveId}/diagnostics:
    get:
      tags:
        - ObjectiveService
        - Objectives
      summary: Get objective context diagnostics
      description: >-
        Returns the context-usage breakdown measured for the objective's most
        recent iteration: character lengths per context component (system
        prompt, memory appendices, tool definitions, messages by role) alongside
        the iteration's input token counts.
      operationId: ObjectiveService_GetObjectiveDiagnostics
      parameters:
        - name: workspaceId
          in: path
          required: true
          schema:
            type: string
            example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
        - name: objectiveId
          in: path
          description: >-
            The ID of the objective. Supports "external_id:" prefix for external
            IDs.
          required: true
          schema:
            example: obj_01HXKD2E5NQM3T9AYWCFQAZGFV
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetObjectiveDiagnosticsResponse'
        default:
          description: Default error response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Status'
      x-codeSamples:
        - lang: JavaScript
          source: >-
            import Cadenya from '@cadenya/cadenya';


            const client = new Cadenya({
              apiKey: process.env['CADENYA_API_KEY'], // This is the default and can be omitted
            });


            const response = await
            client.objectives.retrieveDiagnostics('obj_01HXKD2E5NQM3T9AYWCFQAZGFV',
            {
              workspaceId: 'workspace_01HXKD2E5NQM3T9AYWCF133E3Q',
            });


            console.log(response.diagnostics);
        - lang: Python
          source: |-
            import os
            from cadenya import Cadenya

            client = Cadenya(
                api_key=os.environ.get("CADENYA_API_KEY"),  # This is the default and can be omitted
            )
            response = client.objectives.retrieve_diagnostics(
                objective_id="obj_01HXKD2E5NQM3T9AYWCFQAZGFV",
                workspace_id="workspace_01HXKD2E5NQM3T9AYWCF133E3Q",
            )
            print(response.diagnostics)
        - lang: Go
          source: "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"go.cadenya.com/cadenya-go\"\n\t\"go.cadenya.com/cadenya-go/option\"\n)\n\nfunc main() {\n\tclient := cadenya.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Objectives.GetDiagnostics(\n\t\tcontext.TODO(),\n\t\t\"obj_01HXKD2E5NQM3T9AYWCFQAZGFV\",\n\t\tcadenya.ObjectiveGetDiagnosticsParams{\n\t\t\tWorkspaceID: cadenya.String(\"workspace_01HXKD2E5NQM3T9AYWCF133E3Q\"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response.Diagnostics)\n}\n"
        - lang: Ruby
          source: |-
            require "cadenya"

            cadenya = Cadenya::Client.new(api_key: "My API Key")

            response = cadenya.objectives.retrieve_diagnostics(
              "obj_01HXKD2E5NQM3T9AYWCFQAZGFV",
              workspace_id: "workspace_01HXKD2E5NQM3T9AYWCF133E3Q"
            )

            puts(response)
        - lang: CLI
          source: |-
            cadenya objectives retrieve-diagnostics \
              --api-key 'My API Key' \
              --workspace-id workspace_01HXKD2E5NQM3T9AYWCF133E3Q \
              --objective-id obj_01HXKD2E5NQM3T9AYWCFQAZGFV
components:
  schemas:
    GetObjectiveDiagnosticsResponse:
      required:
        - diagnostics
      type: object
      properties:
        diagnostics:
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/ObjectiveDiagnostics'
          description: Diagnostics from the objective's most recent iteration.
    Status:
      type: object
      properties:
        code:
          type: integer
          description: >-
            The status code, which should be an enum value of
            [google.rpc.Code][google.rpc.Code].
          format: int32
        message:
          type: string
          description: >-
            A developer-facing error message, which should be in English. Any
            user-facing error message should be localized and sent in the
            [google.rpc.Status.details][google.rpc.Status.details] field, or
            localized by the client.
        details:
          type: array
          items:
            $ref: '#/components/schemas/GoogleProtobufAny'
          description: >-
            A list of messages that carry the error details.  There is a common
            set of message types for APIs to use.
      description: >-
        The `Status` type defines a logical error model that is suitable for
        different programming environments, including REST APIs and RPC APIs. It
        is used by [gRPC](https://github.com/grpc). Each `Status` message
        contains three pieces of data: error code, error message, and error
        details. You can find out more about this error model and how to work
        with it in the [API Design
        Guide](https://cloud.google.com/apis/design/errors).
    ObjectiveDiagnostics:
      required:
        - contextLengths
        - inputTokens
        - cachedInputTokens
      type: object
      properties:
        contextLengths:
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/ContextLengths'
          description: Measured character lengths per context component.
        inputTokens:
          readOnly: true
          type: integer
          description: >-
            Input tokens reported by the LLM provider for the iteration's
            completion.
          format: int32
        cachedInputTokens:
          readOnly: true
          type: integer
          description: |-
            The portion of input_tokens served from the provider's prompt cache.
             Lets clients distinguish "big but cached" from "big and paid fresh
             every iteration".
          format: int32
      description: >-
        ObjectiveDiagnostics is the context-usage breakdown measured for a
        single
         iteration at request-assembly time. It reports how much of the context
         window each component occupies so tool parameters, memory cascades, and
         prompts can be tuned against real token usage.
    GoogleProtobufAny:
      type: object
      properties:
        '@type':
          type: string
          description: The type of the serialized message.
      additionalProperties: true
      description: >-
        Contains an arbitrary serialized message along with a @type that
        describes the type of the serialized message.
    ContextLengths:
      required:
        - systemPrompt
        - skillsMemory
        - episodicMemory
        - availableTools
        - toolDefinitions
        - userMessages
        - assistantMessages
        - toolResults
      type: object
      properties:
        systemPrompt:
          readOnly: true
          type: integer
          description: >-
            Character length of the objective's base system prompt (rendered
            variation
             template). Not tokens -- see the message comment.
          format: int32
        skillsMemory:
          readOnly: true
          type: integer
          description: >-
            Character length of the skills memory appendix attached to the
            system prompt.
          format: int32
        episodicMemory:
          readOnly: true
          type: integer
          description: >-
            Character length of the episodic memory appendix attached to the
            system prompt.
          format: int32
        availableTools:
          readOnly: true
          type: integer
          description: >-
            Character length of the discoverable/available-tools appendix
            attached to the
             system prompt.
          format: int32
        toolDefinitions:
          readOnly: true
          type: integer
          description: >-
            Character length of the serialized tool definitions sent with the
            completion
             request (names, descriptions, and JSON-schema parameters).
          format: int32
        userMessages:
          readOnly: true
          type: integer
          description: Character length of the chat history messages with the user role.
          format: int32
        assistantMessages:
          readOnly: true
          type: integer
          description: >-
            Character length of the chat history messages with the assistant
            role.
          format: int32
        toolResults:
          readOnly: true
          type: integer
          description: Character length of the tool results present in the chat history.
          format: int32
      description: >-
        ContextLengths is the measured character length of each distinct
        component
         of an iteration's assembled context window. Values are raw character
         lengths of the component as assembled into the request — token estimates
         are derived by the client against input_tokens (component share =
         component length / sum of all lengths).

         New components are added as new fields — wire-compatible; absent
         components read as 0.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````