Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,11 @@ Determine:
1. **Source provider** (the value emitted in `source_provider`): one of `openai` / `anthropic` (1P) / `google` (Gemini, including Vertex AI) / `cohere` / `custom` (OpenAI-compatible). §7.1.2 below distinguishes Vertex AI internally for §12 only — the public enum stays at these 5 values so downstream agents don't need to learn a new branch.
2. **AI framework**: raw SDK / LangChain / LlamaIndex / Vercel AI SDK / custom
3. **SDK version**: read from lockfile or manifest
4. **Same model family**: defaults to `false`. Set `same_model_family: true` ONLY when ALL plan model mappings go from Anthropic 1P (direct `anthropic` SDK) to Bedrock Claude — in that case the prompt-adaptation step is skipped downstream. Mixed projects (e.g. chat=Anthropic→Claude AND embeddings=OpenAI→Cohere) → `false`.
4. **Same model family**: defaults to `false`. Set `same_model_family: true` when ALL plan model mappings keep the model itself, which is now true in two cases:
- Anthropic 1P (direct `anthropic` SDK) → Bedrock Claude, and
- OpenAI → **the same OpenAI model on Bedrock**, i.e. every `aws_model_id` is a proprietary GPT model (`openai.gpt-5*`) matching its `source_model`.

In both cases the prompt-adaptation step is skipped downstream, because the model is unchanged. Mixed projects (e.g. chat=Anthropic→Claude AND embeddings=OpenAI→Cohere) → `false`. A GPT source mapped to Claude/Nova/`gpt-oss` is a model change → `false`.

## 7.1.1 Disambiguate `openai` vs OpenAI-compatible

Expand Down Expand Up @@ -240,6 +244,8 @@ If `source_provider ∈ {openai, google}` AND `same_model_family == false`, scan

For any other source_provider (`anthropic`, `cohere`, `custom`) OR `same_model_family == true`, set `behavior_deltas: []` and skip the rest of this section.

**Exception — OpenAI same-model on mantle.** When `source_provider == openai` AND `same_model_family == true` (every target is a proprietary `openai.gpt-5*` model), do NOT emit `behavior_deltas: []` wholesale. The model is unchanged, so the parameter-surface deltas (temperature range, penalties, stop sequences) genuinely do not apply — but the **API surface** can still change. Read only the "Same-model (mantle) deltas" section of the reference's `openai-to-bedrock.md` and emit those: Chat Completions → Responses, reasoning items round-tripping, endpoint path and credential, and prompt-caching availability. Skipping these would leave a `chat.completions.create` call pointed at a model that does not verifiably accept it.

1. Read the `behavior-delta-detection` reference at the absolute path given in your
context block's `behavior-delta-detection reference:` line. Call that file's directory
`<BDD_DIR>` (strip the filename from that path).
Expand Down Expand Up @@ -308,7 +314,7 @@ find <REPO> -type f \( \( -name "*.json" -path "*langsmith*" \) -o \( -name "*.j

- `cohere` / `custom` / `unknown` / empty — no stable HTTP contract callable with stdlib alone.
- `errors` contains the EXACT substring `vertex AI auth detected (ADC, not API key)` (per §7.1.2) — Vertex AI uses ADC, not API keys; pasting a Gemini API key against Vertex would 401. Match the full phrase to avoid false hits from other `errors` entries that happen to contain "vertex".
- `same_model_family == true` (Anthropic 1P → Bedrock Claude) — the evaluator skips quality scoring entirely, so a live baseline adds no value.
- `same_model_family == true` (Anthropic 1P → Bedrock Claude, or OpenAI → the same GPT model on Bedrock) — the evaluator skips quality scoring entirely, so a live baseline adds no value. The source and target are the same model, so a baseline would be comparing it against itself.

Set `source_baseline_available` from the `Source baseline available:` line in your context — the orchestration skill sets it to `true` when the user already supplied a key in Phase B3, `false` otherwise. Echo that value; do not hardcode either way (hardcoding `false` would clobber an already-collected key's signal for the evaluator downstream).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Read from prompt context (forwarded from llm2bedrock-code-analyzer, llm2bedrock-
- `files_to_modify` — list of `"<file>: <change>"`. §10 iterates over this exact list.
- `dependencies_to_replace` — list of `"<old-pkg> -> <new-pkg>"`. §12 applies these to the manifest.
- `behavior_deltas` — list of parameter-surface differences. The user ALREADY confirmed each one at the orchestration checkpoint; §9 applies the confirmed decisions.
- `same_model_family` — `true` for Anthropic 1P → Bedrock Claude. Skip prompt adaptation in §10.
- `same_model_family` — `true` when the model itself is unchanged: Anthropic 1P → Bedrock Claude, or OpenAI → the same GPT model on Bedrock (`openai.gpt-5*`). Skip prompt adaptation in §10, and leave model parameters (`temperature`, penalties, stop sequences) untouched — they did not change.
- `special_patterns` — `{streaming, function_calling, embeddings, vision}` booleans. Drives §8 examples to apply.
- **From `llm2bedrock-prompt-evaluator`** (T2-4) — adapted prompts (if any) at `<repo>/.saws-migrate/eval-results/adapted_prompts.jsonl`. §10 step 2 injects these where applicable.
- **`Confirmed behavior-delta decisions file (Read it):`** — a context line naming `<Phase results directory>/delta-decisions.json`. `Read` that file: a JSON array where each entry carries a behavior delta and the user's chosen resolution/option (`[]` = none). §9 applies these EXACTLY as decided.
Expand Down Expand Up @@ -152,27 +152,65 @@ If your context has a `Rewrite strategy: mantle` line, use the **Mantle express

The source SDK stays. Per client, change only three things:

- **base_url** → `https://bedrock-mantle.<REGION>.api.aws/v1` (OpenAI-compatible SDKs) or `https://bedrock-mantle.<REGION>.api.aws/anthropic/v1` (Anthropic SDK).
- **base_url** → depends on the target model family. Pick from this table; getting it wrong returns 404, not a helpful error:

| Target model | base_url |
| ---------------------------------------- | ------------------------------------------------------ |
| Proprietary OpenAI GPT (`openai.gpt-5*`) | `https://bedrock-mantle.<REGION>.api.aws/openai/v1` |
| Other OpenAI-compatible targets | `https://bedrock-mantle.<REGION>.api.aws/v1` |
| Anthropic SDK | `https://bedrock-mantle.<REGION>.api.aws/anthropic/v1` |

If your context has a `Mantle base path` line, use it verbatim — it is authoritative over this table.
- **Credential** → a Bedrock bearer token, NOT the original provider key, read from the `AWS_BEARER_TOKEN_BEDROCK` env var. Do not leave the old `api_key=os.environ["OPENAI_API_KEY"]` line in place.
- **Model ID** → the Bedrock model id from the `Mantle model map` context line (the `aws_model_id` from the migration plan).

OpenAI SDK example:
**When your context has `Same model: true`**, the target is the same model the app already used. Do NOT change model parameters (`temperature`, penalties, stop sequences) — they are unchanged, and §9 will not ask about them. Limit edits to base_url, credential, and model id, plus the Chat Completions → Responses reshape below if the source used Chat Completions.

OpenAI SDK example — proprietary GPT target (note the `openai/v1` path):

```python
# Before
from openai import OpenAI
client = OpenAI() # api_key from OPENAI_API_KEY

# After (Mantle — same SDK)
# After (Mantle — same SDK, same model)
import os
from openai import OpenAI
client = OpenAI(
base_url="https://bedrock-mantle.us-east-1.api.aws/v1",
base_url="https://bedrock-mantle.us-east-1.api.aws/openai/v1",
api_key=os.environ["AWS_BEARER_TOKEN_BEDROCK"],
)
# model="gpt-4o" -> model="anthropic.claude-haiku-4-5"
# model="gpt-5.5" -> model="openai.gpt-5.5"
```

A bearer token read from the environment expires within 12 hours. When the target repo has a long-running process (a server, worker, or scheduled job rather than a short CLI run), prefer the auto-refreshing client and note the added dependency in `dependency_changes`:

```python
from aws_bedrock_token_generator import provide_token # aws-bedrock-token-generator
from openai import BedrockOpenAI # openai>=2.45.0

region = "us-east-1"
client = BedrockOpenAI(
aws_region=region,
bedrock_token_provider=lambda: provide_token(region=region),
max_retries=6,
)
```

**Chat Completions → Responses (proprietary GPT targets only).** Chat Completions is unverified for these models; every AWS sample uses Responses. If the source calls `chat.completions.create`, reshape it — this is the one part of the Mantle lane that is not config-only:

```python
# Before
r = client.chat.completions.create(model="gpt-5.5", messages=msgs, max_tokens=512)
text = r.choices[0].message.content

# After
r = client.responses.create(model="openai.gpt-5.5", input=msgs, max_output_tokens=512, store=False)
text = r.output_text
```

For multi-turn or tool-calling flows, append `r.output` to the next request's `input` — these models emit reasoning items that must round-trip, and dropping them degrades quality silently rather than raising an error.

Anthropic SDK example:

```python
Expand All @@ -189,7 +227,9 @@ client = anthropic.Anthropic(
)
```

Do NOT rewrite request/response parsing — the whole point of Mantle is that the source SDK's call and response shapes are preserved. After applying the three changes above, skip the Converse-specific guidance in the rest of §8 and the §9 behavior-delta application still applies normally.
Do NOT rewrite request/response parsing — the whole point of Mantle is that the source SDK's call and response shapes are preserved. The single exception is the Chat Completions → Responses reshape above, which applies only to proprietary GPT targets. After applying the changes above, skip the Converse-specific guidance in the rest of §8; the §9 behavior-delta application still applies normally.

**Never rewrite a proprietary GPT target to Converse.** `openai.gpt-5*` models have no `bedrock-runtime` surface, so a boto3 `converse()` call against one fails at runtime. If your context pairs a `openai.gpt-5*` model id with the Converse path, stop and report the contradiction rather than generating code that cannot work.

### Converse rewrite (default)

Expand Down
Loading
Loading