Skip to content

[BREAKING] FEAT: Add runtime generation configuration - #3506

Open
Nina Chikanov (nina-msft) wants to merge 21 commits into
microsoft:mainfrom
nina-msft:richlundeen-temporary-component-settings
Open

Nina Chikanov (nina-msft) wants to merge 21 commits into
microsoft:mainfrom
nina-msft:richlundeen-temporary-component-settings

Conversation

@nina-msft

@nina-msft Nina Chikanov (nina-msft) commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Description

  • Add typed RequestGenerationConfig metadata for per-request temperature, with strict validation and capability checks.
  • Implement OpenAI Chat overrides using shared model-family and reasoning-mode rules. Request-local resolution handles passthrough precedence and transport retries.
  • Move Generation settings into the composer. Selections persist across sends, and message footers expose saved requested/resolved values and their source, including unknown provider defaults.
  • Remove the obsolete editor temperature-variant creation path from FEAT: Adding Temporary Instance Creation from the Registry #3030.

Breaking REST change: target responses drop supports_temperature_override, reconstructable, and reconstruction_error. Runtime controls use capabilities.supports_temperature instead of temporary-target reconstruction.

GUI screenshots

Local frontend/backend with mocked provider responses.

Composer settings

Generation settings in the composer with temperature set to zero

Per-message evidence

Request and response footers showing a zero-temperature request override

Tests and Documentation

Updated SDK, GUI, model-capability, and registry guides. Added coverage for sampling rules, request evidence, composer/editor behavior, and the REST response shape.

Merged main at 01ce6ca66. Post-merge focused checks passed: 706 Python tests, 329 frontend tests, production build, lint, and types.

Validation commands and results

Runtime generation, sampling rules, backend/editor, and mapper checks: 706 passed.

uv run --no-sync pytest -q tests\unit\prompt_target\target\test_target_capabilities.py tests\unit\prompt_target\target\test_runtime_temperature.py tests\unit\prompt_target\test_discover_target_capabilities.py tests\unit\backend\test_temporary_components.py tests\unit\backend\test_conversation_editor.py tests\unit\backend\test_target_service.py tests\unit\backend\test_mappers.py::TestTargetObjectToInstance tests\unit\backend\test_mappers.py::TestTargetObjectToInstanceRoundRobin tests\unit\backend\test_mappers.py::test_target_instance_reports_effective_history_replay

Python formatting, lint, and types: passed.

$pythonFiles = @(git diff --name-only --cached origin/main -- '*.py' | ForEach-Object { $_ -replace '/', '\' })
$typedFiles = @($pythonFiles | Where-Object { $_ -notlike 'doc\*' })
uv run --no-sync ruff format --check @pythonFiles
uv run --no-sync ruff check @pythonFiles
uv run --no-sync ty check @typedFiles

Frontend production build (including TypeScript) and changed-file ESLint: passed (from frontend).

$files = @(git diff --name-only --relative --cached origin/main -- '*.ts' '*.tsx' | ForEach-Object { $_ -replace '/', '\' })
npm run build
node node_modules\eslint\bin\eslint.js --max-warnings 0 @files

Frontend regressions: 304 passed across eight suites; 25 passed in the ChatWindow/App selection (254 excluded by the selector). From frontend:

$jestArgs = @('--runInBand', '--silent', '--transformIgnorePatterns', 'node_modules/(?!(axios|react-markdown|react-router|@remix-run/route-pattern|cookie-es|remark-.*|rehype-.*|micromark.*|mdast-.*|hast-.*|unist-.*|unified|bail|trough|vfile.*|is-plain-obj|trim-lines|property-information|comma-separated-tokens|space-separated-tokens|decode-named-character-reference|character-entities.*|html-url-attributes|devlop|zwitch|longest-streak|markdown-table|ccount|escape-string-regexp|estree-util-.*|hastscript|web-namespaces|stringify-entities|inline-style-parser|style-to-object)/)')
node node_modules\jest\bin\jest.js @jestArgs --runTestsByPath src\hooks\useConversationDraft.test.ts src\hooks\useConversationSave.test.ts src\hooks\useAttackTargetResolution.test.tsx src\utils\requestGeneration.test.ts src\utils\messageMapper.test.ts src\components\Chat\GenerationSettings.test.tsx src\components\Chat\MessageList.test.tsx src\components\Chat\ChatInputArea.test.tsx
node node_modules\jest\bin\jest.js @jestArgs --runTestsByPath src\components\Chat\ChatWindow.test.tsx src\App.labels.test.tsx --testNamePattern 'runtime temperature|per-send temperature|generation|first-send draft|saved target variant|edits locally|enter edit mode|automatically saving on exit|hosts Chat controls'

Paired capability documentation: 26 cells synchronized.

uv run --no-sync python -c "from pathlib import Path; import jupytext; p=Path(r'doc\code\targets\6_1_target_capabilities'); script=jupytext.read(p.with_suffix('.py')); notebook=jupytext.read(p.with_suffix('.ipynb')); a=[(c.cell_type,c.source) for c in script.cells]; b=[(c.cell_type,c.source) for c in notebook.cells]; assert a == b, 'Paired notebook/script cells differ'; print(f'{len(a)} cells synchronized')"

Notebook code was not executed.

Add a typed per-send contract, initial OpenAI Chat support, durable temperature evidence, and future-send Chat controls while preserving configured target defaults and saved variant bindings.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Use known capability profiles and explicit deployment declarations instead of an adapter model allowlist. Restore send-hook retries and pacing while retaining the first temperature resolution. Document GUI verification and remaining scope.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Preserve web-search validation, manual-chat safeguards, and accessible temperature explanations alongside per-send overrides.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Introduce typed generation envelopes and per-parameter temperature resolution, retaining legacy metadata readers and rejecting conflicting formats.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Comment thread doc/code/targets/0_prompt_targets.md Resolved
@hannahwestra25

Copy link
Copy Markdown
Contributor

could you add screenshots ?

Address Hannah's feedback with per-field capability mapping, a set-based adapter contract, generic parameter resolution, and canonical-only metadata. Keep OpenAI capability updates and send-time mode checks aligned and preserve declarations through discovery.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Remove draft history, design decisions, and duplicate capability explanations; retain a concise usage example, default resolution, validation, and saved evidence.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Use shared sampling rules for runtime support and validation, preserve configured defaults and model lifecycle behavior, and document generic generation configuration.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Add composer generation settings and per-message details. Remove obsolete editor temperature-variant creation. Breaking REST change: remove target reconstructable, reconstruction_error, and supports_temperature_override fields.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Resolve composer, editor-test, and GUI documentation conflicts while preserving generation settings and legacy field cleanup.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
@nina-msft Nina Chikanov (nina-msft) changed the title [DRAFT] FEAT: Allow per-send temperature in OpenAI Chat and Chat UI [DRAFT] [BREAKING] FEAT: Add runtime generation configuration Oct 31, 2026
Resolve runtime temperature support on target instances rather than shared model profiles. Relocate sampling coverage and document the capability boundary.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Copilot AI balanced review requested due to automatic review settings November 2, 2026 19:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

After runtime reinitialization removes temperature support, an existing override can block sending while the disabled checkbox prevents users from clearing it.

1 open issue
What changed in this PR

Adds per-request generation configuration to PyRIT, allowing temperature overrides without changing shared targets or saved bindings. This replaces the GUI’s temperature-specific temporary-target flow introduced in #3030.

Changes:

  • Adds typed request options, capability validation, and OpenAI Chat temperature resolution with saved request/response evidence.
  • Moves generation controls into the composer and displays saved values in message footers.
  • Removes obsolete target response fields and updates tests and documentation.
File Description
tests/​unit/​prompt_target/​test_discover_target_capabilities.py Tests preservation of generation capabilities during discovery.
tests/​unit/​prompt_target/​target/​test_target_configuration.py Verifies generation availability is excluded from identity.
tests/​unit/​prompt_target/​target/​test_target_capabilities.py Tests separation of model profiles and runtime support.
tests/​unit/​prompt_target/​target/​test_runtime_temperature.py Covers validation, sampling rules, persistence, retries, and isolation.
tests/​unit/​prompt_target/​target/​test_prompt_target.py Updates expected response metadata with generation evidence.
tests/​unit/​models/​test_request_generation_config.py Tests generation models and metadata validation.
tests/​unit/​backend/​test_temporary_components.py Tests runtime overrides alongside saved target bindings.
pyrit/​prompt_target/​openai/​openai_chat_target.py Resolves runtime temperature and records submitted values.
pyrit/​prompt_target/​common/​target_configuration.py Excludes generation availability from target hashes.
pyrit/​prompt_target/​common/​target_capabilities.py Clarifies model-profile responsibilities in documentation.
pyrit/​prompt_target/​common/​prompt_target.py Validates request options and associates generation evidence.
pyrit/​prompt_target/​common/​discover_target_capabilities.py Preserves declared fields when resolving capabilities.
pyrit/​models/​target/​target_capabilities.py Adds the runtime temperature capability.
pyrit/​models/​target/​request_generation_config.py Defines request options and resolution evidence.
pyrit/​models/​target/​__init__.py Exports generation models lazily.
pyrit/​models/​catalog/​target.py Removes obsolete target response fields.
pyrit/​models/​__init__.py Exposes generation models through the public package.
pyrit/​backend/​services/​message_send_service.py Validates generation options before submission.
pyrit/​backend/​mappers/​target_mappers.py Removes reconstruction-derived target flags.
frontend/​src/​utils/​requestGeneration.ts Validates, serializes, and displays generation settings.
frontend/​src/​utils/​requestGeneration.test.ts Tests option serialization and evidence display.
frontend/​src/​utils/​messageMapper.ts Maps saved evidence into message display fields.
frontend/​src/​types/​index.ts Adds generation types and updates target responses.
frontend/​src/​services/​targetRegistry.ts Removes temperature-specific target construction.
frontend/​src/​hooks/​useConversationDraft.ts Removes editor temperature-variant state and creation.
frontend/​src/​hooks/​useConversationDraft.test.ts Tests saves without constructing temperature variants.
frontend/​src/​hooks/​useAttackTargetResolution.ts Stops adding obsolete flags to resolved targets.
frontend/​src/​components/​Chat/​PromptEditor.tsx Adds a composer footer slot.
frontend/​src/​components/​Chat/​MessageList.tsx Displays saved generation evidence and details.
frontend/​src/​components/​Chat/​MessageList.test.tsx Tests generation footers and detail popovers.
frontend/​src/​components/​Chat/​MessageList.styles.ts Supports wrapping footers and bounded detail popovers.
frontend/​src/​components/​Chat/​GenerationSettings.tsx Adds capability-aware generation controls.
frontend/​src/​components/​Chat/​GenerationSettings.test.tsx Tests defaults, overrides, and disabled controls.
frontend/​src/​components/​Chat/​GenerationSettings.styles.ts Styles generation controls and summaries.
frontend/​src/​components/​Chat/​ChatWindow.tsx Maintains composer selections and attaches per-send options.
frontend/​src/​components/​Chat/​ChatWindow.test.tsx Tests runtime settings across sends and navigation.
frontend/​src/​components/​Chat/​ChatWindow.styles.ts Removes obsolete temperature-control styles.
frontend/​src/​components/​Chat/​ChatInputArea.tsx Integrates generation settings into the composer.
frontend/​src/​App.labels.test.tsx Updates workspace tests for composer-based settings.
doc/​gui/​0_gui.md Documents generation controls and saved evidence.
doc/​code/​targets/​6_1_target_capabilities.py Documents model-family sampling rules.
doc/​code/​targets/​6_1_target_capabilities.ipynb Synchronizes capability documentation in the notebook.
doc/​code/​targets/​0_prompt_targets.md Documents SDK request options and generation evidence.
doc/​code/​registry/​0_registry.md Separates runtime settings from target reconstruction.

Review effort: Balanced

Reset retained generation settings on target identity changes and allow clearing unsupported overrides. Strip request-only options from synthesized responses while retaining evidence, and preserve explicit null passthrough payloads across retries.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Preserve request-generation controls alongside the shared responsive layout hook from main.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Replace incomplete message mocks so metadata validation exercises real request and response objects without weakening the generation contract.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
@nina-msft
Nina Chikanov (nina-msft) marked this pull request as ready for review November 3, 2026 00:36
@nina-msft Nina Chikanov (nina-msft) changed the title [DRAFT] [BREAKING] FEAT: Add runtime generation configuration [BREAKING] FEAT: Add runtime generation configuration Nov 3, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two minor review notes are inline.

Comment thread doc/code/targets/0_prompt_targets.md Resolved
Comment thread doc/gui/0_gui.md
### Generation settings

Open **Generation settings** in the message composer to override supported
parameters for outgoing messages. For example, to set **Temperature**, uncheck

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is over-explaining, should we remove?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please shorten this rather than remove all guidance. The control already explains persistence, unchanged earlier messages, valid ranges and target defaults. Keep the set/clear action, the attack/target/page-reset rule, and how to inspect saved values; cut the repeated-send snapshot and saved-binding details. That preserves the useful behavior that is not obvious from the control without repeating its help text.

@richlundeen

Copy link
Copy Markdown
Contributor

After trying this in the GUI, I think this is too much UI and text for a single override. The large popover covers the composer, puts the setting far from Send, and requires a checkbox before the actual input. The unsupported state in this screenshot still shows the entire unusable form.

Please simplify it:

  • Move the compact control to the right, directly below the Send arrow.
  • Use one Temperature override field: blank means use the target default, a number overrides it (including 0), and clearing restores the default. Keep validation inline.
  • Move persistence/default explanations into optional help. For unsupported targets, use a short disabled state/reason rather than the full form; any retained override must still be clearable.

This could become a compact request-options area for JSON schema/structured output and other supported parameters later. I'd keep that broader support as a contained follow-up; simplifying this temperature control belongs in this PR.

Generation settings popover covering the chat composer with verbose copy and an unsupported temperature field

@hannahwestra25

Copy link
Copy Markdown
Contributor

agree with Richard Lundeen (@richlundeen) on simplifying the generation settings but I think the whole send input field could use a re-vamp. I like how ghcp does it :
image
which would mean keeping it on the left but that's a nit

Share OpenAI sampling rules, allow explicit capability overrides and unknown model defaults, enforce adapter evidence, and cover backend admission and provider failures.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Resolve Chat and draft conflicts without restoring temperature-only target creation. Integrate generation drafts with upstream navigation restoration and retain upstream scorer behavior.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ff01f02a-4d7d-489e-8dff-0cfb75e59876

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed source at 53f9f06. The inline finding concerns fallback temperature resolution. UI assessment is focused on the supplied desktop screenshots; default, unsupported, error and narrow-layout states were not verified at this head.

Comment on lines +339 to +340
else:
self._apply_request_temperature(body=body, temperature=generation_info.temperature.resolved)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Keep fallback temperatures local to each target

RoundRobinTarget passes the same normalized message between fallback children. With equal model/constructor settings but nested passthrough temperatures of 0.3 and 0.8, both children are accepted. If the first child writes its evidence then fails, for example after rate-limit retries, this branch makes the second send 0.3 instead of its configured 0.8, even with no runtime override. Scope cached evidence to its originating adapter invocation, or clear it between different fallback children, while preserving same-child retry stability.

@richlundeen

Copy link
Copy Markdown
Contributor

The earlier simplification request still applies at this head. Setting one value requires opening the panel, clearing the default checkbox and editing the number. Clearing the number leaves an invalid override that blocks Send rather than restoring the default. A compact optional field can preserve zero, omission and inline errors without the extra checkbox or persistent explanation. The earlier unsupported-override clearing bug is fixed in source; keep that recovery intact.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants