Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ process:
sessionMode: isolated
defaultStrategy: parallel
defaultOnError: continue
temperature: 0.7
persistence:
mode: memory
sqlite_path: memory/checkpoints.db
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-06-23
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
## Context

SubAgents are spawned as separate `node index.js` processes that read their own config.yaml. Currently, temperature is configured only at the provider level (`providers.openai.temperature`) and cannot be adjusted per-subAgent or globally for subAgent invocations. The temperature parameter controls randomness in LLM outputs — lower for precise, deterministic tasks and higher for creative, exploratory work.

The existing pattern for subAgent configuration (timeout, maxConcurrent, sessionMode) uses environment variables passed from the parent process to the spawned child. Temperature should follow this same pattern.

## Goals / Non-Goals

**Goals:**
- Add global default temperature under `process.subAgent.temperature`
- Add per-skill temperature override under `process.subAgent.skills[].temperature`
- Pass temperature to spawned processes via `MADZ_SUBAGENT_TEMPERATURE` env var
- Override provider temperature in spawned processes when env var is set
- Add optional per-call `temperature` parameter to subAgent tool schema

**Non-Goals:**
- Runtime config reloading (temperature changes require restart)
- Temperature validation against specific LLM provider capabilities
- Per-message temperature overrides within a single subAgent session
- UI/CLI configuration interface

## Decisions

### Decision 1: Environment Variable over CLI Argument
**Choice:** Pass temperature via `MADZ_SUBAGENT_TEMPERATURE` environment variable.
**Rationale:** Follows the existing pattern used for timeout configuration. Keeps the spawned process invocation clean. CLI arguments would require modifying the node command line and parsing logic.
**Alternatives considered:**
- CLI argument: More explicit but requires command line modification and parsing
- Config file in temp directory: Overly complex for a single value
- stdin: Unnecessary overhead for a single configuration value

### Decision 2: Resolution Hierarchy
**Choice:** per-call > per-skill config > global config > env var > provider default
**Rationale:** Provides maximum flexibility while maintaining sensible defaults. Per-call override allows ad-hoc adjustments without config changes. Per-skill override allows skill-specific tuning. Global config provides a sensible default for all subAgents.
**Alternatives considered:**
- Config only: Less flexible, requires config changes for every adjustment
- Env var only: Not user-friendly, requires environment setup

### Decision 3: Graceful Degradation
**Choice:** Invalid temperature values fall back to provider default rather than crashing.
**Rationale:** Spawned processes may receive stale or corrupted env vars. Crashing would be worse than using a reasonable default. The parent process continues unaffected.
**Alternatives considered:**
- Hard fail: Safer but creates fragile spawned processes
- Log and continue: Added as optional low-priority enhancement

### Decision 4: Scoped Override
**Choice:** Temperature override only affects the spawned process.
**Rationale:** The parent process should continue using its configured temperature. This prevents unintended side effects and maintains process isolation.
**Alternatives considered:**
- Global override: Would affect all LLM calls in the parent process, unintended side effects

## Risks / Trade-offs

### Risk: Config Schema Validation
**Trade-off:** Adding new optional fields increases config complexity slightly.
**Mitigation:** Fields are optional, existing configs continue to work. Validation is straightforward (0-2 range).

### Risk: Env Var Parsing Errors
**Trade-off:** String-to-float conversion in spawned process may fail.
**Mitigation:** Graceful fallback to provider default. Parse with parseFloat, check isNaN, validate range.

### Risk: Concurrent SubAgent Interference
**Trade-off:** Multiple subAgents with different temperatures must not interfere.
**Mitigation:** Each spawned process has its own environment. Env vars are scoped to the child process only.

### Risk: Backward Compatibility
**Trade-off:** New config fields must not break existing deployments.
**Mitigation:** All fields are optional. Missing temperature falls through to provider default.

## Migration Plan

No migration required. The change is fully backward compatible:
1. Deploy the code change
2. Existing configs continue to work using provider defaults
3. Users can optionally add `temperature` to their config.yaml
4. No database migrations, no config file migrations

## Open Questions

- Should temperature be exposed in the TUI config editor? (Out of scope for this change)
- Should we log temperature overrides for debugging? (Low priority, can be added later)
- Are there LLM providers that don't support temperature? (Provider-specific handling can be added later)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Why

Currently, subAgents are launched without configurable temperature, meaning their behavior is fixed by the default LLM settings. Users may want to adjust temperature per-subAgent or globally to control the randomness of their outputs — lower for precise, deterministic tasks and higher for creative, exploratory work. This limits fine-grained control over subAgent behavior without needing to modify system prompts or skill definitions.

## What Changes

- Add `temperature` field to `process.subAgent` in config.yaml as a global default (0-2 range, OpenAI spec)
- Add `temperature` field to `process.subAgent.skills[].temperature` for per-skill overrides
- Pass temperature to spawned subAgent processes via `MADZ_SUBAGENT_TEMPERATURE` environment variable
- Override provider temperature in spawned processes when env var is set
- Add optional `temperature` parameter to subAgent tool schema for per-call overrides
- Follow resolution hierarchy: per-call > per-skill config > global config > env var > provider default

## Capabilities

### New Capabilities
- `subagent-temperature`: Configure temperature for subAgents via config.yaml with global default and per-skill override support

### Modified Capabilities
<!-- No existing capabilities have spec-level requirement changes -->

## Impact

- **Config:** `config.yaml` — new `process.subAgent.temperature` and `process.subAgent.skills[].temperature` fields
- **Tools:** `src/tools/subAgent.js` — `spawnSubAgentProcess()` passes temperature via env var; tool schema adds optional `temperature` parameter
- **Provider:** `src/provider/openai.js` — `createChatModel()` checks `MADZ_SUBAGENT_TEMPERATURE` env var and overrides provider temperature
- **Backward compatibility:** All changes are additive. Existing configs without temperature continue to work using provider defaults.
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
## ADDED Requirements

### Requirement: Global subAgent temperature configuration
The system SHALL allow users to configure a global default temperature for all subAgents via `process.subAgent.temperature` in config.yaml. Temperature values MUST be floats in the range 0-2 (OpenAI specification). When not configured, subAgents SHALL use the provider default temperature.

#### Scenario: Valid global temperature is accepted
- **WHEN** config.yaml contains `process.subAgent.temperature: 0.7`
- **THEN** the system accepts the value and uses it as the default for all subAgents

#### Scenario: Global temperature at minimum boundary
- **WHEN** config.yaml contains `process.subAgent.temperature: 0`
- **THEN** the system accepts the value and uses deterministic (non-random) outputs

#### Scenario: Global temperature at maximum boundary
- **WHEN** config.yaml contains `process.subAgent.temperature: 2`
- **THEN** the system accepts the value and uses maximum randomness

#### Scenario: Global temperature outside valid range is rejected
- **WHEN** config.yaml contains `process.subAgent.temperature: -0.1` or `process.subAgent.temperature: 2.1`
- **THEN** the system rejects the value with a validation error

#### Scenario: Missing global temperature uses provider default
- **WHEN** config.yaml does not contain `process.subAgent.temperature`
- **THEN** subAgents use the provider default temperature from `providers.openai.temperature`

### Requirement: Per-skill temperature override
The system SHALL allow users to configure a temperature override for specific skills via `process.subAgent.skills[].temperature` in config.yaml. Per-skill temperature MUST take precedence over the global default.

#### Scenario: Per-skill temperature overrides global default
- **WHEN** config.yaml contains global `temperature: 0.7` and skill-specific `temperature: 0.3` for audit-code
- **THEN** audit-code subAgents use 0.3 while other skills use 0.7

#### Scenario: Per-skill temperature without global default
- **WHEN** config.yaml contains only skill-specific `temperature: 0.3` without global temperature
- **THEN** the skill uses 0.3 and other skills use provider default

### Requirement: Temperature passed to spawned process via environment variable
The system SHALL pass the resolved temperature value to spawned subAgent processes via the `MADZ_SUBAGENT_TEMPERATURE` environment variable. The env var MUST only be set when temperature is explicitly configured (not when using provider default).

#### Scenario: Temperature env var is set when configured
- **WHEN** config.yaml contains `process.subAgent.temperature: 0.5`
- **THEN** the spawned subAgent process receives `MADZ_SUBAGENT_TEMPERATURE=0.5`

#### Scenario: Temperature env var is not set when using provider default
- **WHEN** config.yaml does not contain subAgent temperature configuration
- **THEN** the spawned subAgent process does not receive `MADZ_SUBAGENT_TEMPERATURE` env var

#### Scenario: Per-skill temperature env var overrides global
- **WHEN** config.yaml contains global `temperature: 0.7` and skill-specific `temperature: 0.3`
- **THEN** the audit-code subAgent receives `MADZ_SUBAGENT_TEMPERATURE=0.3`

### Requirement: Spawned process overrides provider temperature
The system SHALL override the provider temperature in spawned subAgent processes when `MADZ_SUBAGENT_TEMPERATURE` is set. Invalid env var values MUST fall back gracefully to the provider default.

#### Scenario: Spawned process uses env var temperature
- **WHEN** spawned process has `MADZ_SUBAGENT_TEMPERATURE=0.4`
- **THEN** the LLM call uses temperature 0.4 regardless of provider default

#### Scenario: Invalid env var falls back to provider default
- **WHEN** spawned process has `MADZ_SUBAGENT_TEMPERATURE=invalid`
- **THEN** the LLM call uses the provider default temperature

#### Scenario: Empty env var falls back to provider default
- **WHEN** spawned process has `MADZ_SUBAGENT_TEMPERATURE=` (empty string)
- **THEN** the LLM call uses the provider default temperature

#### Scenario: Parent process temperature unchanged
- **WHEN** spawned process has `MADZ_SUBAGENT_TEMPERATURE=0.4` and parent has provider temperature 0.7
- **THEN** parent process LLM calls continue using 0.7

### Requirement: Per-call temperature override
The system SHALL accept an optional `temperature` parameter in the subAgent tool invocation. Per-call temperature MUST take precedence over all config levels (per-skill, global, provider).

#### Scenario: Per-call temperature overrides all config
- **WHEN** subAgent is called with `temperature: 0.9` and config has global `0.7`
- **THEN** the subAgent uses temperature 0.9

#### Scenario: Per-call temperature validation
- **WHEN** subAgent is called with `temperature: 3.0` (out of range)
- **THEN** the system rejects the call with a validation error

#### Scenario: Per-call temperature without config
- **WHEN** subAgent is called with `temperature: 0.5` and no config temperature
- **THEN** the subAgent uses temperature 0.5

### Requirement: Resolution hierarchy
The system SHALL resolve temperature using the following priority order: per-call parameter > per-skill config > global config > provider default.

#### Scenario: Full resolution hierarchy
- **WHEN** per-call=0.9, per-skill=0.3, global=0.7, provider=0.5
- **THEN** resolved temperature is 0.9 (per-call wins)

#### Scenario: Fallback through hierarchy
- **WHEN** no per-call, per-skill=0.3, global=0.7, provider=0.5
- **THEN** resolved temperature is 0.3 (per-skill wins)

#### Scenario: Global fallback
- **WHEN** no per-call, no per-skill, global=0.7, provider=0.5
- **THEN** resolved temperature is 0.7 (global wins)

#### Scenario: Provider fallback
- **WHEN** no per-call, no per-skill, no global, provider=0.5
- **THEN** resolved temperature is 0.5 (provider default)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## 1. Config Schema Updates

- [ ] 1.1 Add `temperature` field to `process.subAgent` section in config.yaml with default value 0.7
- [ ] 1.2 Add `temperature` field to `process.subAgent.skills[].temperature` for per-skill overrides
- [ ] 1.3 Add config validation for temperature range (0-2) and type (float)
- [ ] 1.4 Add config validation tests for valid, invalid, and missing temperature values

## 2. SubAgent Process Temperature Propagation

- [ ] 2.1 Read resolved temperature in `spawnSubAgentProcess()` following hierarchy: per-call > per-skill > global > provider default
- [ ] 2.2 Pass temperature to spawned process via `MADZ_SUBAGENT_TEMPERATURE` environment variable
- [ ] 2.3 Only set env var when temperature is explicitly configured (not when using provider default)
- [ ] 2.4 Add tests for temperature env var propagation with various config scenarios

## 3. Provider Temperature Override in Spawned Process

- [ ] 3.1 Check `MADZ_SUBAGENT_TEMPERATURE` env var in `createChatModel()` in src/provider/openai.js
- [ ] 3.2 Parse env var as float and validate range (0-2)
- [ ] 3.3 Override provider temperature when env var is set and valid
- [ ] 3.4 Fall back to provider default when env var is invalid, empty, or missing
- [ ] 3.5 Ensure parent process temperature remains unchanged (scoped override)
- [ ] 3.6 Add tests for provider temperature override with valid, invalid, and missing env vars

## 4. Per-Call Temperature Override

- [ ] 4.1 Add optional `temperature` parameter to subAgent tool schema
- [ ] 4.2 Validate per-call temperature range (0-2)
- [ ] 4.3 Pass per-call temperature to spawned process (overrides env var and config)
- [ ] 4.4 Add tests for per-call temperature override scenarios

## 5. Integration and Verification

- [ ] 5.1 Verify resolution hierarchy: per-call > per-skill > global > provider default
- [ ] 5.2 Verify concurrent subAgents with different temperatures don't interfere
- [ ] 5.3 Run full test suite and verify all tests pass
- [ ] 5.4 Run lint and verify no lint errors
- [ ] 5.5 Verify application starts without crashing
Loading
Loading