mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
python-sdk/v0.1.96
1734 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
70f15d6ead | Merge remote-tracking branch 'origin/main' into codex/fac-127-ms-agent-stable-apis | ||
|
|
0b854047e2 | fix(ms-agent-python): preserve Azure AD auth | ||
|
|
9a103a0348 |
chore(examples): put the AgentCore example on uv projects (#6672)
## What Converts `examples/integrations/agentcore` from unlocked `requirements.txt` files to uv projects (`pyproject.toml` + `uv.lock`), matching every other Python integration example in this repo. ## Why The example already used uv as an *installer* — the agent images are built from `ghcr.io/astral-sh/uv` and ran `uv pip install -r requirements.txt` — but nothing was locked, so each image build re-resolved transitive dependencies against whatever PyPI had that day. That had already drifted into a hard break. `langgraph==1.0.10rc1` resolved alongside a `langgraph-prebuilt` that reads `ExecutionInfo` off `langgraph.runtime`, which 1.0.x does not export, so the LangGraph agent raised `ImportError` at container start. ## The migration - Both agents get a `pyproject.toml` + `uv.lock`; the Dockerfiles install with `uv sync --locked` and run out of `/app/.venv`. - LangGraph agent moves to `langgraph==1.1.6` / `langchain==1.2.15`, the pair used by `examples/integrations/langgraph-python`, which resolves the import failure. `langchain` was previously `>=0.3.0` while the code uses the 1.x `create_agent` API. - Four packages that shipped code imports directly were declared nowhere and survived only as transitives: `boto3` (both agents, via `agents/utils/ssm.py`), `PyJWT` (langgraph, via `agents/utils/auth.py`), `langchain-core` (langgraph, via `tools/todos.py`), `botocore` (root, via `scripts/utils.py`). All now declared; no resolved version changed. - `aws-opentelemetry-distro` moves from a loose second `uv pip install` into the locked set. - The example root gets a project for the `scripts/` helpers. Their `requirements.txt` listed the dependencies but nothing installed it, so `uv run scripts/test-agent.py` — the command that script's own docstring gives — failed on a missing `requests`. - Deploy and local-dev scripts call `uv run` instead of bare `python3`; preflight checks for `uv` rather than `python3`. ## Terraform The docker-mode image hash read `patterns/<pattern>/requirements.txt`, `patterns/utils`, a root-level `gateway/` and `tools/`, and a root `pyproject.toml` — none of which exist here. `filesha256` on a missing file is a plan-time error. Repointed at `agents/<pattern>` and `agents/utils`, now hashing `pyproject.toml` and `uv.lock`. The hash then had to exclude the virtualenv the migration creates: `fileset(pattern_dir, "**/*.py")` saw 3114 files instead of 5, and the computed hash differed depending on whether a developer had ever run the agent locally — feeding `replace_triggered_by` and forcing a runtime replacement. Measured: `5f9a98ef…` with a venv present vs `bacab1e1…` without, on identical committed sources. The fix filters `.venv/` and `venv/` and produces the clean-checkout digest in both cases. ## Review Five review rounds plus a promotion audit, and nine defects this migration introduced were found and fixed before merge. Each fix was verified by running the thing, not by reading it: - The image hash sweeping the local virtualenv (above). - The undeclared direct dependencies (above). - `scripts/test-agent.py` piped the child's output and never drained it, deadlocking the agent, while the startup-timeout branch blocked forever on a read — the only channel carrying uv's lockfile-drift error. - `--local` treated any listener on port 8080 as the agent, so a foreign process produced "Agent started successfully" while the real child died. Adopting a running process is now explicit opt-in. - The documented invocation contract had drifted across the two READMEs and both scripts' usage text; a single reconciliation pass now owns all of them, and every documented command was executed to confirm it works. - The Terraform README named the CloudFormation deploy script, which cannot read a Terraform deployment. - Two `.env.example` entries parsed as their own trailing comment text under Docker Compose. - The build context shipped 898 MB of local-only artifacts (measured); now 11 kB. - Assorted comment and message inaccuracies, including a container env block whose comment attributed a runtime-critical variable to uv. ## Repository hygiene Two fixes the pre-merge gates surfaced rather than the review rounds: - `oxfmt` on the example README and `tofu fmt` on the Terraform locals file. The README break was introduced by this branch; the Terraform one predates it but sits in a file this branch edits. - The Terraform ignore rules were anchored to the top level, so the provider cache `terraform init` writes beside every *nested* module was fully stageable — a measured 834 MB one `git add -A` from being committed. Switched to unanchored patterns, matching what this branch already did for the virtualenv layout. Verified with `git check-ignore` that the nested cache and lock file are now covered, tfstate and tfvars still are, and no tracked file is caught by the wider patterns. ## Not addressed Roughly 90 further findings are real but pre-existing and belong to four follow-up subjects, listed in full in the review ledger: - **Terraform module repair** — `terraform validate` fails on five undeclared resources, so this module cannot plan at all. Zip mode references an entry point and a packager directory that do not exist. - **test-agent AG-UI correctness** — the request body fails `RunAgentInput.model_validate` on both agents, and the response decoder parses a pre-AG-UI format, so failures print nothing and exit 0. - **README accuracy** — a `docs/` directory that does not exist, a wrong Node floor, a teardown block whose second command never runs. - **Deploy-script hardening** — `infra-terraform/scripts/deploy-frontend.py` requires a Terraform output nothing declares, so it exits 1 every run; the README now says so rather than presenting it as a working path. ## Verification Both images built for `linux/arm64` and the agent module imported inside each, after every fix cycle. `uv lock --check` clean on all three projects. Every documented command executed from its documented directory. The virtualenv hash filter, the build-context reduction, the pipe deadlock, the port-adoption fix and the env-file parsing were each verified by measurement with before/after output. No repo CI job builds or lints this example, so these local runs are the only coverage that exists. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
9e488f7a51 |
test(examples): gate the starters' Intelligence wiring block on one shape (closes OSS-982) (#6716)
**Merge order: #6711 → #6718 → this PR.** #6718 rewrites `identifyUser` in the same 22 blocks and is a sibling of this branch, not stacked on it, so the two overlap on the same lines. Landing the gate last means it ratchets on the finished shape and avoids a conflict. If this PR goes first instead, #6718 goes red until it moves all 22 sites together — which is the gate working, but noisier. Stacked on #6711 — merge that first. This branch descends from it, so the diff below carries its commit too; GitHub drops those once #6711 lands. Basing this PR on `main` rather than on #6711's branch is deliberate: 17 of 35 workflows filter `pull_request: branches: [main]`, including the one this PR extends, so a PR based on the 981 branch would not run the check it adds. ## Problem The marked block that wires managed Intelligence is the region a hosted reader copies verbatim, and nothing checked it. Both gaps are deliberate, not accidental: - `examples/integrations/_parity/manifest.json` lists `src/app/api/copilotkit/**` under `allowedDivergence` for every instance it tracks. What parity does hold byte-identical is the demo frontend: 54 verbatim paths of example canvas, todo columns and charts. - No `examples/integrations/*/docker-compose.test.yml` sets `COPILOTKIT_LICENSE_TOKEN`. The wiring is a ternary on that variable, so all 13 smoke-tested starters take the else arm. The `intelligence:` arm has never executed in CI, in any starter. The cost was already visible. The block's code was byte-identical in 21 of 22 starters, but its warning comment had drifted into five variants and the two `ms-agent-framework-*` starters shipped the `demo-user` stub with no warning at all. Comment drift is harmless by itself; it is the tracer showing nothing held the region still, and it is how the localhost default of #6711 survived in all 22 copies at once. ## Change `scripts/validate-intelligence-wiring-block.ts` greps the opening marker, compares every site against the north-star starter, and fails on the first line that differs. Two normalisations keep it usable: - The block is dedented, because `agentcore` nests it two levels deeper — its runtime is a Lambda handler, not a Next.js route. - The else arm's runner name is masked, because `agentcore` runs `AgentCoreRunner` in front of a Bedrock AgentCore session where an in-process runner has nothing to run. `EXPECTED_RUNNER` holds that one exception, so a runner swapped in by accident still fails. Everything else, comment text included, must match to the byte. Then the warning is unified at all 22 sites on the fullest existing wording, which also says the id must exist in Intelligence or thread operations can fail. It compares against the north star rather than a literal kept in the script, so improving the block means editing `langgraph-python` and running the other 21 to match. ## What it does and does not guarantee It is a shape gate, not a content gate: 22 identically wrong copies still pass. What it guarantees is that a fix reaches all of them or none. The check passes on day one — 21 of 22 already matched on code — so it is a ratchet, not a migration. ## Verification Mutating a real starter three ways, each caught: | Mutation | Reported as | | --- | --- | | Dropped one comment line | `line 15 differs from the north star`, exit 1 | | \`InMemoryAgentRunner\` → \`SomeOtherRunner\` | `else arm uses SomeOtherRunner; expected InMemoryAgentRunner` | | Reintroduced \`?? \"http://localhost:4201\"\` | `line 6 differs`, both sides shown | The third matters: the #6711 regression is now caught at a second site, independent of the env-name validator. Commands run, all exit 0: - `pnpm exec vitest run scripts/__tests__/validate-intelligence-wiring-block.test.ts scripts/__tests__/validate-intelligence-env-names.test.ts` — 30 passed - `pnpm check:intelligence-wiring-block` — `All 22 Intelligence wiring sites match langgraph-python.` - `pnpm check:intelligence-env-names` — unaffected, still canonical - `pnpm parity:verify` - `oxfmt --check`, `oxlint`, and `tsc --noEmit --strict` on the new pair Two tests guard the gate against going vacuous: one asserts at least 22 marker files are discovered, so an empty violation list cannot pass on an empty file list. Not run locally: the lefthook pre-commit suite, which fails environmentally in a worktree without per-package installs (`sh: vite: command not found`). This diff touches no package source. ## Not covered Enrolling the `intelligence:` arm in the smoke path. It needs a license token in CI secrets and an endpoint reachable from the compose network — a different size of job, tracked separately. |
||
|
|
888a70e169 | Merge branch 'main' into chore/agentcore-uv | ||
|
|
4b73ce3c83 |
fix(examples): stop overriding the managed Intelligence URL defaults (closes OSS-981) (#6711)
## What does this PR do? `CopilotKitIntelligence` is built to be correct when the caller says nothing: omitting `apiUrl`/`wsUrl` resolves to `https://api.intelligence.copilotkit.ai` and `wss://realtime.intelligence.copilotkit.ai`, and its docstring says so outright — *"leaving both unset is always correct against it."* Every starter's runtime route defeated that default: ```ts apiUrl: process.env.INTELLIGENCE_API_URL ?? "http://localhost:4201", wsUrl: process.env.INTELLIGENCE_GATEWAY_WS_URL ?? "ws://localhost:4401", ``` With the variables unset — the correct configuration for a managed user — the `??` supplies localhost and the runtime aims at a local stack that is not running. This is the artifact `copilotkit init` clones, so it is the first thing a new managed user runs. The starter's own `.env.example` already warns about exactly this failure, two files away: > `INTELLIGENCE_API_URL` and `INTELLIGENCE_GATEWAY_WS_URL` point at a self-hosted or local Intelligence deployment only — leave them unset when using managed Intelligence, or the channel host and runtime will try to reach a local stack that usually is not running. So the documentation was right and the code contradicted it. `channel-host.mts`, in the same directories, already had the correct shape. ### The fix **22 runtime wiring sites** (20 route handlers, `adk-angular/server.ts`, and the AgentCore Lambda) now use the conditional spread these starters already use in `channel-host.mts`, so a self-hosted override still works and the managed default applies when absent: ```ts ...(process.env.INTELLIGENCE_API_URL ? { apiUrl: process.env.INTELLIGENCE_API_URL } : {}), ``` No hosted URL is written into the examples — the library already owns them, so this is a deletion. **3 `.env.example` files** (`agent-spec`, `llamaindex`, `mcp-apps`) set the same values *uncommented*. Two do it directly beneath a comment telling the reader to leave them unset, and an `.env.example` is copied to `.env`, so these were the remaining route to a localhost value once the code default was gone. Commented out to match the other nineteen starters; `agent-spec` had no explanation at all and gets the standard one. **A guard**, added to the existing `scripts/validate-intelligence-env-names.ts` rather than a new script — it already polices the canonical Intelligence key name and the two dead hosts, and its workflow is deliberately unfiltered so it sees every README, example and skill. Two rules: `managedUrlFallback` (a `??`/`||` default on either variable) and `managedUrlEnvFileAssignment` (an uncommented env-example assignment). The rule is the *pattern*, not the literal, so a staging host substituted for localhost fails the same way. Five files legitimately want a local target and are allowlisted with their reasons: the `playwright.config.ts` and `.env.example` of the banking and reskinnable-demo showcases (own vendored compose ports 7050/7053 and 7250/7253, own seeded org keys) and `agentcore/docker/.env.example` (the documented local development stack). Resolving those to the managed hosts would aim an offline test suite at production. `scripts/__tests__` has no general runner, so the workflow runs this test file explicitly, following the `plugin-skills-check.yml` precedent — otherwise a rule that silently stopped matching would leave the check passing on an empty result. ## Related PRs and Issues - Closes OSS-981. - Supersedes the canceled ENT-922, whose blocker ("do not invent hosted URLs; rewrite once the managed env contract is final") no longer applies: the contract shipped as `MANAGED_INTELLIGENCE_API_URL` / `MANAGED_INTELLIGENCE_WS_URL`, and the fix removes a fallback rather than adding a URL. - ENT-949 shipped a warning for this class of mistake, but `warnOnPartialHostOverride` only fires on a *partial* override — both values defaulting to localhost together is not partial, so nothing warned. ## Verification - `pnpm exec vitest run scripts/__tests__/validate-intelligence-env-names.test.ts` — 13 passed. Written first: the rules were red before they existed, then reported **48 violations across 24 files** for the code rule and **10 across 5** for the env-file rule; the fixes took both to green. - `pnpm check:intelligence-env-names` — exit 0. - `oxfmt --check` and `oxlint` over all 25 touched files — clean. - The spread typechecks under `strict` + `exactOptionalPropertyTypes`, the setting that would reject `apiUrl: string | undefined`. - The marked wiring block stays byte-identical across 21 of 22 starters (`agentcore` differs only in its runner), and no `localhost` remains inside any marked block. - Not run locally: the 13 starter Next builds. `test_smoke-starter.yml` typechecks the route handlers in CI on this PR. ### Out of scope `agentcore/docker/docker-compose.yml` keeps its `${INTELLIGENCE_API_URL:-http://localhost:4201}`: it is compose substitution in the documented local-dev stack, not shipped runtime code. Separately that default cannot work anyway — inside the bridge container `localhost` is the container's own loopback — but that is a different bug. ## Checklist - [x] I have read the [Contribution Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md) - [x] If the PR changes or adds functionality, I have updated the relevant documentation - [x] "Allow edits by maintainers" is checked 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
f8e13e675c |
Remove the banking showcase in favor of reskinnable-demo (#6683)
## What Sunsets `examples/showcases/banking`. It is superseded by `examples/showcases/reskinnable-demo`, which ships the same banking experience as one of its runtime-swappable skins (alongside airline) on top of a shared shell. Keeping both means maintaining two copies of the same demo. 160 files deleted, plus the five places that pointed at the app: | File | Change | | --- | --- | | `pnpm-workspace.yaml` | Drops the workspace entry. Also fixes the adjacent NOTE, which attributed the canary AG-UI pin to "banking's agent" when it is reskinnable-demo's own Python deep agent that needs it. | | `pnpm-lock.yaml` | Regenerated (−919/+12). The 12 additions are peer-suffix re-keying caused by removing the importer — banking pinned a different `eslint`/`vitest` peer combination. No dependency version changes. | | `examples/README.md` | The banking row becomes a reskinnable-demo row, so the successor is listed and the showcase count is unchanged. | | `showcase/shell-docs/src/content/docs/faq.mdx` | The "Banking Assistant" link retargets to reskinnable-demo instead of 404ing. | | `.github/config-allowlist.txt` | Drops the deleted `next.config.mjs`. | Note that banking was a real pnpm workspace member using `workspace:*` deps, unlike reskinnable-demo, which sits deliberately outside the workspace with its own lockfile. That is why the root lockfile has to be regenerated here. ## Deliberately not changed - `scripts/migrate-demos.sh` and `scripts/archive-demo-repos.sh` still name `examples/showcases/banking`. Those are the already-executed one-shot manifests for the repo consolidation; the path is a historical record in them, not a live reference. - `reskinnable-demo`'s `.env.example` and `docker-compose.yml` still explain their +200 port offset in terms of banking's stack. The offset stays real, and "was cloned from banking" stays true. - The `banking` mentions in `test_reskinnable-demo.yml` refer to reskinnable-demo's **banking skin**, not this app. ## Verification - `.github/scripts/check-config-allowlist.sh` passes. - A full `pnpm install` agrees with the regenerated lockfile (no further diff). - The lockfile-only regen and the full install produce identical output. The `test-and-check-packages` pre-commit hook fires on any `pnpm-lock.yaml` change, so it ran `test,publint,attw` across all 25 packages. Four suites failed locally — `sqlite-runner`, `web-inspector`, `vue`, `react-core` — in a worktree installed with `--ignore-scripts`, which skips `better-sqlite3`'s native build. This change touches no package source, so CI is the gate on those; please confirm they are green here before merging. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
7a24a2d855 | fix(ms-agent-python): migrate starter to stable APIs | ||
|
|
314f1ca55d |
fix(examples): stop overriding the managed Intelligence URL defaults (closes OSS-981)
CopilotKitIntelligence resolves apiUrl/wsUrl to the managed hosts when they are omitted, and its own docstring says leaving both unset is always correct against the managed service. Every starter's runtime route supplied `?? "http://localhost:4201"` instead, so a managed reader who copied the block got a runtime aimed at a local stack that is not running -- the failure the starter's own .env.example warns about two files away. Replace the fallbacks with the conditional spread these same starters already use in channel-host.mts, so a self-hosted override still works and the managed default applies when it is absent. Three .env.example files also set the values uncommented, two of them directly under a comment telling the reader to leave them unset; comment those out to match the other nineteen starters. Guard both shapes in validate-intelligence-env-names.ts, which already polices the canonical Intelligence key name and hosts and runs unfiltered on every PR. The rule is the pattern rather than the literal, so a staging host substituted for localhost fails the same way. Local e2e harnesses and demo stacks that genuinely target a local deployment are allowlisted with their reasons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
e21af7f5c2 |
Merge main into FAC-128 Slack manifest fix
# Conflicts: # pnpm-lock.yaml |
||
|
|
93861b428d | fix(web-inspector): polish inspector chrome, threads, and dark mode | ||
|
|
84dd86f2ed |
test(examples): gate the starters' Intelligence wiring block on one shape (closes OSS-982)
The marked block that wires managed Intelligence is the region a hosted reader copies verbatim, and nothing checked it. Both gaps were deliberate: the parity manifest lists `src/app/api/copilotkit/**` under `allowedDivergence` for every instance it tracks, and no `docker-compose.test.yml` sets `COPILOTKIT_LICENSE_TOKEN`, so every smoke-tested starter takes the else arm and the `intelligence:` arm has never run in CI. The cost was already visible. The block's code was byte-identical in 21 of 22 starters, but its warning comment had drifted into five variants and the two `ms-agent-framework-*` starters shipped the `demo-user` stub with no warning at all. That drift is how the localhost default of OSS-981 survived in all 22 copies at once. Add `scripts/validate-intelligence-wiring-block.ts`, which greps the opening marker, compares every site against the north-star starter, and fails on the first line that differs. Two normalisations keep it usable: the block is dedented, because `agentcore` nests it deeper, and the else arm's runner name is masked, because `agentcore` runs `AgentCoreRunner` in front of a Bedrock session where an in-process runner has nothing to run. Everything else, comment text included, must match to the byte. Then unify the warning at all 22 sites on the fullest wording, which also says the id must exist in Intelligence or thread operations can fail. The check passes on day one, so it is a ratchet rather than a migration. It is a shape gate, not a content gate: 22 identically wrong copies still pass. What it guarantees is that a fix reaches all of them or none. Not covered: enrolling the `intelligence:` arm in the smoke path. That needs a license token in CI and a reachable endpoint from the compose network, and is tracked separately. |
||
|
|
8483f434f7 |
fix(examples): stop overriding the managed Intelligence URL defaults (closes OSS-981)
CopilotKitIntelligence resolves apiUrl/wsUrl to the managed hosts when they are omitted, and its own docstring says leaving both unset is always correct against the managed service. Every starter's runtime route supplied `?? "http://localhost:4201"` instead, so a managed reader who copied the block got a runtime aimed at a local stack that is not running -- the failure the starter's own .env.example warns about two files away. Replace the fallbacks with the conditional spread these same starters already use in channel-host.mts, so a self-hosted override still works and the managed default applies when it is absent. Three .env.example files also set the values uncommented, two of them directly under a comment telling the reader to leave them unset; comment those out to match the other nineteen starters. Guard both shapes in validate-intelligence-env-names.ts, which already polices the canonical Intelligence key name and hosts and runs unfiltered on every PR. The rule is the pattern rather than the literal, so a staging host substituted for localhost fails the same way. Local e2e harnesses and demo stacks that genuinely target a local deployment are allowlisted with their reasons. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
1983c07ccf |
fix(examples): add missing zod for the OpenRouter demo-server
@ai-sdk/openai imports zod/v4 at runtime. The Angular OpenRouter demo-server did not declare that peer, so chat failed on Windows pnpm. |
||
|
|
fd7f2fa683 | Merge origin/main into alem/hud-arrow-color | ||
|
|
b3b339f544 |
Revert "feat(web-inspector): add Event Snippets and save-as-snippet (#6649)"
This reverts commit |
||
|
|
79c02f0f02 |
style(web-inspector): fewer layers on the launcher, a lens for its dot (#6688)
## What does this PR do? Design review on the launcher and its notification dot asked for three things: a milder face than solid black, fewer borders and background layers, and a subtle shadow in place of the dot's heavy border. This is all three, plus the removal of six utilities that never had any effect. Everything here was compared side by side at production size, on a light *and* a dark host page, before it was chosen. Two of my own first proposals were dropped after measuring them, both described below. **Two concerns, three commits.** `4fa38d91f` and `cd711b369` are the launcher itself — the package change, 2 files. `295f75495` gives the react-router lab a dark mode, because a dark host page is what this change has to be judged against and the lab could not produce one. If you would rather review those separately, say so and I will split them. ## The face `#181C1F` at 95%, which review asked for. Worth recording so it does not come up again: the near-black the review saw was `#010507`, 20.5:1 against white. What shipped yesterday was already `#1C1F24` at 16.5:1, so this value is a hair *darker* than the one it replaces (17.2:1) and the difference between them is a ΔE of 2.3, at the floor of what an eye can separate. It settles the question rather than changing the look. ## Fewer layers Six Tailwind utilities on the launcher set properties the unlayered `css` block sets again — `bg-slate-950/95`, `border-white/20`, `ring-1`, `ring-white/10` and the two hover variants. Unlayered declarations beat layered ones regardless of specificity or source order, so none of them has ever had any effect. Each was the package's only use, so the checked-in stylesheet drops 980 bytes. Of the *visible* layers, two went: **The outer hairline.** The launcher carried two concentric lilac rings: the border, and a second one 1px outside it as a box-shadow. The outer one also hardcoded the lilac rather than reading `--cpk-launcher-edge`, so it silently could not follow the token. It is replaced by a one-pixel light edge along the top, which is what keeps the face from reading flat without drawing a frame. **`backdrop-blur-md`.** It sat behind a 95%-opaque fill and bought close to nothing, while mounting a permanent blur compositing layer over a customer's page. **The border stays, and this is the finding that changed my mind.** I first proposed removing it too. Against a dark host page the face measures 1.10:1 (GitHub dark), 1.04:1 (Tailwind slate-900) and 1.22:1 (black) — indistinguishable from the page. The border is the only thing that gives the launcher an outline there. It is not decoration. ## The dot The collar was `1.5px`, opaque, zero blur, and 21% of the dot's footprint. Because the dot's centre sits *on* the rim, its outer half painted a hard dark crescent onto the **host page** rather than onto the launcher — which is what read as "heavy". A hairline plus a soft drop separates it just as well. The fill becomes a lens lit from the upper left. Both stops are derived from `--cpk-launcher-signal`, so a new tone needs no new values; verified for the rose error tone and the violet announcement tone. **Dropped after looking at it:** a coloured glow around the dot. It was the obvious reading of "more premium", but the launcher already pulses in that same colour when a failure is new, and a permanent glow competes with the thing that is supposed to draw the eye. **Also dropped:** tinting the border in the signal colour, which was suggested in review. On a dark page the border is the entire silhouette, so tinting it recolours the whole launcher for a state that can persist for hours. ## One non-obvious consequence Removing the blur removed a side effect nobody had written down: `backdrop-filter` promotes the element to its own compositing layer. Without a layer, the hover `scale(1.05)` re-rasterises the mark every frame and it visibly jitters — geometrically nothing moves, the mark's centre holds to three decimals, but the vector is re-rendered at fractional offsets. `will-change: transform` asks for the layer directly and the jitter is gone. Confirmed by eye on the running demo before this was chosen. ## Tests `packages/web-inspector` stays at **28 files / 611 tests**, all passing. No new tests. The colour tests here are deliberately token-shaped rather than value-shaped — they assert the custom property and the *sharing* of one face and one edge between the launcher and its pill, never a hex — so face and edge values are free to move and this change is exactly the kind they were written to allow. The one test that constrains it, `"the pill and the launcher share one surface and one edge"`, still passes. What is genuinely unguarded, and was before this PR too: the dot's collar width, the double hairline, and the Tailwind class list. Asserting rendered geometry would need a browser test runner, which this package does not have — jsdom computes no layout. ## How to see it `pnpm --filter react-router-example dev`, then `http://localhost:5173`. The launcher is top right; `Break runtime` arms the error tone and `Break run` the announcement one. Hover it to check the mark no longer jitters. One thing worth knowing while reviewing: the launcher anchors top-right and is `position: fixed` on an element mounted directly under `<body>`, so on this page it sits over the lab's toolbar. Drag it to the lower right and it is out of the way. ## The lab's dark mode A dark host page is where the launcher's border earns its place, and the lab had no way to produce one, so reviewing this change was not possible without it. It follows `examples/v2/react/demo` rather than inventing anything: the host owns a `theme` state, and `CopilotChat` gets `className="dark"` — which is what makes the package swap its own variable set. The colours are the demo's by another route; it writes the oklch literals CopilotKit's variables use, and those are Tailwind's neutral steps (`neutral-950` is `oklch(0.145 0 0)`, `neutral-50` is `oklch(0.985 0 0)`, `neutral-800` is `oklch(0.269 0 0)`). Measured identical on the running lab. `@custom-variant dark (&:is(.dark *))` is needed in the lab's stylesheet because Tailwind v4 points `dark:` at `prefers-color-scheme` by default, so the toggle would have lost to the OS. Same declaration the package uses for its own sheet. Two details that are decisions rather than oversights. The **error banner keeps a rose tint** in dark mode instead of going neutral, because an error banner that looks like every other surface is not an error banner. And the **toolbar buttons keep a visible on/off contrast** — active inverts to a light face, inactive sits on `neutral-800` — because the lab's whole purpose is knowing which failure is currently armed. My first attempt stripped every background instead of theming, and that is worth recording because it looked plausible: the chat bubble, the send button, the button states and the banner all collapsed into one flat grey. The chat paints its own surfaces and has to be told what theme it is in, not undressed. ## A separate bug found on the way `CopilotKitProvider` documents `inspectorDefaultAnchor` — *"Default anchor corner for the inspector button and window"* — and it has no effect. `defaultAnchor` is typed on the React wrapper and forwarded to the element, but the string `defaultAnchor` does not occur anywhere in `packages/web-inspector`, so it lands as `defaultanchor="[object Object]"` and is ignored. The corner stays hardcoded `{ horizontal: "right", vertical: "top" }` in two places. Not fixed here, to keep this PR to one concern. It is worth fixing: any host with a top navigation bar hits exactly this, finds exactly that prop, and it does nothing. ## Related PRs and Issues - Follows #6646 |
||
|
|
1602ac3bb7 |
updated with-mcp-use README to not have stale references (#3614)
Removed redundant text and improved clarity in the README. Removed stale and internal references ## What does this PR do? Fixed the Readme references for the open mcp app example, it was referencing stale docs folder which does not exist. ## Related PRs and Issues - (Direct link to related PR or issue, if relevant) ## Checklist - [ *] I have read the [Contribution Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md) - [ ] If the PR changes or adds functionality, I have updated the relevant documentation |
||
|
|
c59c1c891b |
fix(showcases): make MCP Apps deployable (#6634)
# fix(showcases): make MCP Apps deployable ## Summary - keep the approved `@copilotkit/*` `1.68.1` upgrade and frontend Railway health check - import the endpoint stack and built-in agent from `@copilotkit/runtime/v2`, matching the current `examples/integrations/mcp-apps` runtime pattern - align MCP Apps on one AG-UI `0.0.58` client/core/encoder/proto graph with `@ag-ui/mcp-apps-middleware@^0.0.3` - replace the stale standalone pnpm lock with the npm lock consumed by Docker, and make Docker install it deterministically with `npm ci --legacy-peer-deps` - remove only unused frontend direct dependencies; `@copilotkit/react-core`, `@copilotkit/runtime`, and `@copilotkit/shared` remain direct `1.68.1` dependencies, while the separately packaged MCP server retains its own `zod@^4.3.5` ## Root cause and RED evidence - Baseline commit: `0daa38f9a7e50522e246a273802ef3ffde92556b` on current `origin/main` `c2abbea9cf`. - `./node_modules/.bin/tsc -p examples/showcases/mcp-apps/tsconfig.json --noEmit --pretty false` reproduced three compatibility failures: `TS2305` for `createCopilotEndpoint`, `TS2305` for `InMemoryAgentRunner`, and `TS2345` because `MCPAppsMiddleware` and the runtime resolved incompatible `@ag-ui/client` types. - Before production edits, `npm test` ran the new compatibility contract and failed `3/3` assertions for the legacy runtime entrypoint, stale AG-UI versions, and missing npm lockfile. - Before changing the Docker install command, the deployment contract failed `1/4` because the Dockerfile still used `npm install --legacy-peer-deps`. - The first Docker build sent `889.11 MB` because no `.dockerignore` excluded host `node_modules` and `.next`; the final context is `5.64 kB`. ## GREEN and verification evidence - PASS — scoped formatter: repo-pinned `oxfmt --check` exited `0` for the changed source, contract, and manifest inputs. - PASS — scoped lint: repo-pinned `oxlint` reported `0 warnings` and `0 errors` for the changed route and compatibility test. - PASS — explicit typecheck: standalone `./node_modules/.bin/tsc --noEmit --pretty false` exited `0`. - PASS — focused tests: `npm test` passed `5/5` contracts covering the v2 runtime entrypoint, AG-UI graph, npm lock truth, deterministic Docker install, and Docker context exclusions. - PASS — production build: `npm run build` compiled, typechecked, generated all four static pages, and emitted the `/api/copilotkit/[[...slug]]` dynamic route. - PASS — npm lock/install truth: `npm ci --legacy-peer-deps --ignore-scripts` installed `1,234` packages from `package-lock.json`; `npm ls @ag-ui/client @ag-ui/core @ag-ui/encoder @ag-ui/proto --all` showed every instance deduped/overridden to `0.0.58`. - PASS — no-cache container gate: `docker build --no-cache -f Dockerfile -t codex-mcp-apps-pr .` completed `npm ci`, the in-image Next production build, image export, and unpack on `node:20-slim` with exit `0`. - PASS — scope/secret/type hygiene: the final PR changes only `examples/showcases/mcp-apps/**`; high-confidence secret patterns, type suppressions, swallowed catches, and floating calls were absent from the staged diff. - PASS — branch commit: `db929211253c5f6e4a9567833bdb0d4b6e7c7d8c` (`fix(showcases): align MCP Apps runtime graph`), following the approved deployability commit without modifying its Railway file. ## Non-blocking warnings - npm reports 10 transitive audit findings (5 low, 1 moderate, 4 high); this compatibility change does not force unrelated breaking upgrades. - The Node 20 container install emits `EBADENGINE` warnings for transitive `@azure/*`, `@typespec/ts-http-runtime`, and `openai@7.5.0` packages that declare Node 22, but the clean Node 20 install and production build both complete successfully. The existing `node:20-slim` base is intentionally unchanged because the gate did not reproduce a failure. - Local Next builds inside the monorepo warn about the root pnpm lock plus the standalone npm lock; the standalone build still completes successfully and Docker uses only the showcase-local npm lock. |
||
|
|
1ebeae46c2 |
fix(world): preserve LangGraph assistant config (#6631)
# fix(world): preserve LangGraph assistant config ## Summary - restore the World demo's browser-supplied OpenAI key under `assistantConfig` - preserve the behavior of the authoritative legacy World commit - add a dependency-free migration contract test ## Verification - rebased cleanly onto current `main` at `c2abbea9cf6a48c22b1dcd19e9dc469d5cfd458f` - verified the authoritative legacy source still uses `assistantConfig` at `markmdev/copilotkit-world@7a27a37b628b9e339d1284ec42382008e67884f5` - verified `@ag-ui/langgraph@0.0.7` declares, stores, and merges `assistantConfig` - regression check against current `main` failed for the expected missing-`assistantConfig` reason; the branch's dependency-free Node test passed (`1/1`) - `oxfmt --write` plus `oxfmt --check` passed on both changed files - Nx reported no affected lint targets; direct `oxlint` completed with `0` errors and one pre-existing `NextRequest` type-import warning on the unchanged import line - root dependency bootstrap passed with the repository-pinned pnpm `10.33.4` and `--frozen-lockfile --ignore-scripts` - `nx run @copilotkit/runtime-client-gql:build` and its 13 dependency builds passed; this does not make that package resolvable from the independently managed nested ChatKit Studio workspace - exact-base and branch World typechecks used the same pnpm `9.15.0` provisioning: base reports seven diagnostics, branch reports six, and the branch-only diagnostic count is zero - the removed base diagnostic is the changed route's invalid `config` property; all six remaining diagnostics are identical current-`main` errors in unchanged `page.tsx`, `useCountryData.ts`, and `countryData.ts` - both production builds compiled the optimized application source; base then failed on the invalid `config`, while the branch advanced past the changed route and stopped on the pre-existing undeclared `@copilotkit/runtime-client-gql` import - Python agent compilation passed - worktree is clean; commit `a25941f9017fcd2a0a8e7660fe768c69cfaa28b6` changes only the World route and its migration contract test ## Existing baseline debt The branch introduces no type or production-build regression and removes the route error it targets. Six unrelated current-`main` type diagnostics remain: ```text src/app/page.tsx(14,42): error TS2307: Cannot find module '@copilotkit/runtime-client-gql' src/hooks/useCountryData.ts(2,50): error TS2307: Cannot find module 'geojson' src/hooks/useCountryData.ts(4,51): error TS2307: Cannot find module 'topojson-specification' src/hooks/useCountryData.ts(32,27): error TS2345: Argument of type 'unknown' is not assignable to parameter of type 'string'. src/hooks/useCountryData.ts(43,12): error TS7006: Parameter 'country' implicitly has an 'any' type. src/utils/countryData.ts(1,40): error TS2307: Cannot find module 'geojson' ``` The nested ChatKit Studio frozen install also reproduces the separate current-`main` Playground importer drift covered by D006. D007 no longer changes `package.json`, so it does not duplicate that lockfile fix. Legacy source: `markmdev/copilotkit-world` at `7a27a37b628b9e339d1284ec42382008e67884f5`. |
||
|
|
96773e56dc |
fix(showcases): sync chatkit studio lockfile (#6630)
# fix(showcases): sync chatkit studio lockfile ## Summary - remove stale ESLint importer entries from the shared ChatKit Studio lockfile - restore frozen-lockfile validation for Playground, Studio, and World without reserializing the lockfile - keep the change limited to the shared dependency contract required by the Playground deployment ## Verification - Formatter: N/A for the changed YAML lockfile. The repository's oxfmt 0.36.0 does not accept YAML targets (`Expected at least one target file`); its full-repository check listed only 28 pre-existing files outside this branch's one-file diff. - YAML parsing and structural validation passed: lockfile version 9.0, four exact manifest importers, 1,431 packages, and 1,431 snapshots. - The shared four-project workspace completed `pnpm install --frozen-lockfile --ignore-scripts` with repository-pinned pnpm 9.15.0; the resolution step was skipped because the lockfile is current. - Playground and Studio passed explicit `tsc --noEmit`; their Next.js production builds also passed. Both Python agent modules compiled successfully, and the workspace defines no JavaScript test suite. - Lint is N/A for this lockfile-only diff: Playground and Studio's existing `next lint` scripts prompt to create an ESLint configuration, while World defines no lint script. - World's existing source/dependency type errors reproduce in both `tsc --noEmit` and `next build`; they are unrelated to the removed ESLint-only importer metadata. World otherwise compiled before its existing type-validation failure. - Diff, scope, secret, and worktree hygiene passed: the commit changes only `examples/showcases/chatkit-studio/pnpm-lock.yaml` with 24 deletions and no additions. |
||
|
|
295f75495e |
feat(examples): give the inspector lab a dark mode like the react demo
The launcher floats over a customer's page, and its border only earns its place against a dark one -- so reviewing this branch needs a dark host page, and the lab had no way to produce one. Copied from `examples/v2/react/demo` rather than invented: the host owns a theme state, and `CopilotChat` gets `className="dark"`, which is what makes the package swap its own variable set. My first attempt stripped every background instead, which is why the chat bubble, the send button, the toolbar's on/off states and the error banner all vanished into one flat grey -- the chat paints its own surfaces and has to be told, not undressed. The colours are the demo's, by another route: it writes the oklch literals that CopilotKit's variables use, and those are Tailwind's neutral steps -- `neutral-950` is `oklch(0.145 0 0)`, `neutral-50` is `oklch(0.985 0 0)`, `neutral-800` is `oklch(0.269 0 0)`. Measured identical on the running lab. `@custom-variant dark (&:is(.dark *))` is needed because Tailwind v4 points `dark:` at `prefers-color-scheme` by default, so the toggle would have been ignored in favour of the OS. Same declaration the package uses for its own sheet. The toggle sits top left, where the react demo puts it. Top right is where the launcher floats. |
||
|
|
d7ac976636 | fix(web-inspector): preserve independent error signals | ||
|
|
e3dafff825 |
chore(examples): remove banking showcase in favor of reskinnable-demo
The banking showcase is superseded by `examples/showcases/reskinnable-demo`, which ships the same banking experience as one of its runtime-swappable skins (alongside airline) on top of a shared shell. Keeping both means maintaining two copies of the same demo, so banking is sunset here. Removes the app and the things that referenced it: - `pnpm-workspace.yaml` — drops the workspace entry. Also fixes the adjacent NOTE, which attributed the canary AG-UI pin to "banking's agent" when it is reskinnable-demo's own Python deep agent that needs it. - `pnpm-lock.yaml` — regenerated. Only the removed importer and the peer-suffix re-keying it caused; no dependency version changes. - `examples/README.md` — the banking row becomes a reskinnable-demo row, so the successor is listed and the showcase count is unchanged. - `showcase/shell-docs/.../faq.mdx` — the Banking Assistant link retargets to reskinnable-demo instead of 404ing. - `.github/config-allowlist.txt` — drops the deleted `next.config.mjs`. Not changed: `scripts/migrate-demos.sh` and `scripts/archive-demo-repos.sh` still name `examples/showcases/banking`. Those are the already-executed one-shot manifests for the repo consolidation; the path is a historical record there, not a live reference. reskinnable-demo's `.env.example` and `docker-compose.yml` likewise still explain their +200 port offset in terms of banking's stack — the offset stays real, and "was cloned from banking" stays true. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
306ddaa5df |
Merge remote-tracking branch 'origin/main' into lukas/oss-903-presentation-wire-errors-notifications-to-emanate-from-and
# Conflicts: # packages/web-inspector/src/lib/__tests__/telemetry.test.ts # packages/web-inspector/src/styles/generated.css |
||
|
|
ba4260ad66 |
feat(web-inspector): add Event Snippets and save-as-snippet (#6649)
Open Inspector Event Snippets on localhost. You can compile, save, and replay AG-UI events in chat. Chat shows a bookmark icon next to a tool call, an A2UI block, or generative UI. Click the icon to save that turn as a snippet. ## What does this PR do? This PR adds the Inspector Event Snippets pane. You can: - Compile a snippet from a recipe (tool-call, reasoning, text, activity, raw) - Save snippets in origin-scoped localStorage (`cpk:inspector:event-snippets`) - Import and export snippets from the pane header - Replay a snippet into live chat through Inspector-only Core inject Each Run remints `messageId`, `parentMessageId`, `toolCallId`, and `runId`. The second Run of the same snippet is a new turn. On localhost, chat shows a bookmark icon beside a tool call, A2UI block, or generative UI. The icon is absolutely positioned. It hangs to the right when there is room. Otherwise it hangs to the left. The card stays full chat width. The React demo adds `sayHello`, `getTime`, `addNumbers`, and a **Call 3 tools** suggestion. ## Related PRs and Issues - Linear [OSS-874](https://linear.app/copilotkit/issue/OSS-874/new-features-also-allow-users-to-emit-specific-events-from-the) ## Checklist - [x] I have read the [Contribution Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md) - [x] If the PR changes or adds functionality, I have updated the relevant documentation - [x] "Allow edits by maintainers" is checked (lets us help iterate on your PR directly — faster turnaround for everyone) ## Testing ### Commands run 1. Lefthook pre-commit ran `nx` targets `test`, `publint`, and `attw` for 27 affected projects. All passed. 2. I did not run `pnpm test:pr` (full repo). Lefthook ran the affected package matrix only. ### Manual test 1. Run `pnpm demo:react` from the repo root. 2. Open http://localhost:3000 3. Open Inspector and select Event Snippets. 4. In chat, click **Call 3 tools**. Confirm three tool cards at full chat width, with the bookmark hanging outside the card. 5. Click a bookmark, then click Run twice. Chat shows a second turn with new IDs. ### How this PR makes testing easy - `packages/web-inspector/src/lib/__tests__/event-snippets.test.ts` - `packages/core/src/__tests__/inspect-inject.test.ts` (covers two injects) - React demo: `examples/v2/react/demo/src/app/page.tsx` ## Linked issues Linear [OSS-874](https://linear.app/copilotkit/issue/OSS-874/new-features-also-allow-users-to-emit-specific-events-from-the) ## Risk / rollback - If ID remint is wrong, a second Run can no-op or duplicate a turn. - The save icon shows on localhost Inspector (or when `showDevConsole` is `true`). - Rollback: revert this PR. ## Public API change **Before** Angular has no Inspector service. ```ts // no CopilotInspector export from @copilotkit/angular ``` **After** ```ts import { CopilotInspector } from "@copilotkit/angular"; const inspector = inject(CopilotInspector); inspector.openInspector({ messageId: "msg-1", menu: "event-snippets", }); ``` React and Vue apps that already mount Inspector on localhost need no new caller code. Chat wires the bookmark through Inspector context. `@copilotkit/core` exports `ɵinjectInspectorEvents` for Inspector only. App code must not call it. There is no public Core emit API. |
||
|
|
dfa78fd231 |
fix(agentcore): ignore terraform provider caches under nested modules
The Terraform ignore rules were anchored to `infra-terraform/…`, which matches only the root provider cache. `terraform init` writes one next to every module, and the nested copies are the large ones: 834MB under infra-terraform/modules/backend/ was fully stageable, one `git add -A` from being committed. Switch the two cache patterns to unanchored `**/` forms, matching what this branch already did for the `venv/` layout. Verified with git check-ignore: the root cache, the nested cache and the nested lock file are all ignored now, tfstate and tfvars still are, and no tracked file (checked against modules/backend/locals.tf) is caught by the widened patterns. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f3dc78891b |
style(agentcore): apply oxfmt to the README table and tofu fmt to locals.tf
The Prerequisites table in examples/integrations/agentcore/README.md picked up a uv row whose URL is wider than the existing column padding, leaving the table unaligned against oxfmt (the repo formatter covers .md — see the lint-fix glob in lefthook.yml). Re-run oxfmt --write on that one file. locals.tf fails tofu fmt on a pre-existing misalignment in the Lambda source-path block that this branch did not introduce; since the file is already in this branch's diff, align it here so every changed .tf file passes tofu fmt -check. Scoped to locals.tf only — modules/backend/copilotkit_runtime.tf has the same class of debt but is out of this diff and is left alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
9cea7fde33 |
fix(agentcore): exclude local-only artifacts from the docker build context
`examples/integrations/agentcore/.dockerignore` covered only cdk.out, node_modules, __pycache__, *.pyc and the two venv layouts. Everything else a developer generates in this tree — the Terraform provider cache, tfstate, terraform.tfvars, config.yaml, docker/.env, generated aws-exports.json, the Vite build output, amplify-deploy.zip, egg-info — was uploaded to the daemon on every build. The context is this directory and three consumers share it: the Terraform local-exec build in infra-terraform/modules/backend/runtime.tf, infra-terraform/scripts/build-and-push-image.sh, and the CDK DockerImageAsset in infra-cdk/lib/backend-stack.ts. Scope of the harm: both agent Dockerfiles COPY explicit paths and never `COPY . .`, so none of this reached a published image layer — there is no credential leak. The cost is context transfer on every build, and CDK asset-hash churn: DockerImageAsset fingerprints the whole context, so an unrelated local file change re-tags and re-pushes the image. Measured with a throwaway `FROM alpine / COPY . /ctx` probe against a context carrying a realistic set of local-only files (871424 KB .terraform provider cache plus the rest): before: 165 files, 877112 KB in-image, 897.74 MB transferred in 20.7s after: 144 files, 2476 KB in-image, 11.26 kB transferred The 21 dropped paths are exactly the intended ones; nothing else disappeared and nothing was added. Both agent images then rebuilt clean with --no-cache for linux/arm64, and `import langgraph_agent` / `import strands_agent` each printed OK inside the resulting containers. All *.example templates survive. The file now reaches full parity with the sibling .gitignore, and adds **/.DS_Store (covered by the repo-root .gitignore). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
fddfcfe742 |
fix(agentcore): stop two .env.example entries parsing as their own comment text
|
||
|
|
2e2fbf2181 |
fix(agentcore): stop --local adopting an unidentified listener on port 8080
`3df7d6764a` hardened `start_local_agent` so a pre-existing listener on 8080
could not be mistaken for the child it just spawned. That hardening never ran.
`main()`'s `--local` branch probed the port first and, on a successful TCP
connect, printed "Agent already running on localhost:8080" and skipped
`start_local_agent` entirely - the function is called from exactly one place,
the `else` of that same probe. So in the one scenario the hardening existed for,
a stranger owning 8080, the hardened code was unreachable and the tester chatted
with the stranger under a success banner, exit 0.
A bare TCP accept only establishes that *some* process is listening. It cannot
establish that the process is this example's agent. The fix removes the check
that made that inference:
- `main()` no longer probes 8080 on the start path at all. Adopting a listener
is now opt-in via `--use-running-agent`, and even then it is announced as
unverified ("did not start it and cannot verify it is an agent") rather than
as "Agent already running". The flag errors out when nothing is listening, and
argparse rejects it without `--local` instead of silently ignoring it.
- The port check moved into `start_local_agent`, before the "Starting local
agent" banner, where it now REFUSES on an occupied port instead of spawning a
child that cannot bind. Because `main()` no longer duplicates the probe, this
is the only port check on the start path, so it is genuinely reachable from
the shipped CLI - which is precisely what the previous attempt was not.
- With the pre-spawn refusal in place, the loop's `not port_already_busy` guard
became a provably-constant conjunct and was folded away. The durable half of
the earlier hardening, polling the child for liveness BEFORE looking at the
port, is unchanged and still reachable.
Same-pattern audit of the file found one more instance: `run_chat` printed
"[Completed in Xs]" purely because `invoke_agent` returned, which it also does
after an HTTP error. `invoke_agent` now returns a bool and the line reports
"[Failed in Xs]" when the exchange did not succeed. The request payload and the
streaming decoder are deliberately untouched (deferred).
Verified by driving the real `main()` via importlib against a foreign HTTP
server bound to 127.0.0.1:8080:
- pre-fix, `--local`: "Agent already running on localhost:8080" then
"Agent: I am a STRANGER on 8080, not the agentcore agent", exit 0.
- post-fix, `--local`: "Port 8080 is already accepting connections" plus how to
proceed, exit 1, nothing spawned.
- post-fix, `--local --use-running-agent`: talks to it, labelled unverified.
- post-fix, `--local --use-running-agent` with nothing listening: exit 1.
- ordinary path (port free, child really binds 8080): "Agent started
successfully", byte-identical to pre-fix output.
- child exits 1 with no listener: still caught in ~1s, not 30s.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
3df7d6764a |
fix(agentcore): stop a foreign listener on 8080 masking a dead agent child
The startup wait loop in start_local_agent checked the port before polling the child, so any process already listening on 8080 satisfied the port check on the very first iteration. The function printed "Agent started successfully" and returned while the real child was dying, and the caller then chatted with the impostor - the exact failure the fail-fast poll() was added to surface. Two changes, because reordering alone is not enough: on the first iteration a doomed child has not exited yet, so a pre-existing listener would still be mistaken for it. - poll() now runs before the port check, so an already-exited child is always reported with its exit code instead of being masked. - Port ownership is snapshotted before the spawn (check_port_available() returns True when the port is OCCUPIED, despite its name). When 8080 was already busy, an open port is no longer accepted as proof this child is serving; the child that cannot bind will exit and be reported with its real exit code, and the timeout message names the port conflict. Fully attributing a listener to a specific child would need a readiness signal from the agent itself (identity endpoint or handshake); refusing to trust a pre-existing listener is the smaller change that keeps the reported outcome truthful. Verified by driving the real function via importlib with a shimmed child: - foreign listener on 8080 + child exits 1: was "Agent started successfully" (returned a process that was dead 0.5s later), now "Agent exited with code 1 before port 8080 opened" and exit 1. - port free + child really binds 8080: still "Agent started successfully" and the live process is returned. - port free + child exits 1: still caught in ~1s, no 30s timeout burn. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
25b4fecbc5 |
docs(agentcore): converge the one uv/deploy contract across the files that state it
The AgentCore example states its Python-tooling and deploy contract in six places — two READMEs, four script self-docs, terraform.tfvars.example, the Terraform variable descriptions and .gitignore. There is only one contract, but each of the last three review rounds corrected a single copy of it, so the copies drifted apart and now contradict each other. This pass reconciles all of them against measured behaviour instead of patching one more surface. What the contract actually is, verified by running each command: - test-agent.py imports boto3/requests/colorama, so it runs under uv with no --project flag. `uv run` resolves the script path against the shell's cwd, not the project root, so `--project ..` is redundant, not required: both forms load infra-terraform/scripts/test-agent.py and both reach the same `FileNotFoundError: 'terraform'`. The script's Usage block claimed the flag was needed; it no longer does. - deploy-frontend.py (Terraform) is standard-library only with a 3.8 floor, so uv is optional. `uv run --no-project` and plain `python3` stop identically at "terraform is not installed". Its "Requires: uv" line said otherwise. - That same script cannot succeed at all. It requires a Terraform output named feedback_api_url; no root or module outputs.tf declares one (only an SSM parameter of that name). Fed the exact output set that outputs.tf does declare, it exits 1 at "Missing required Terraform outputs: feedback_api_url" before any build or upload. The README documented it as the working path for a Terraform deployment; it now says what happens and points at infra-cdk. Repairing the script or declaring the output is tracked separately. - agents/ holds two uv projects plus agents/utils/, which both Dockerfiles COPY in and which has no pyproject.toml or lockfile. "Each agent is its own uv project" overstated the guarantee. - docker mode needs Docker running but no separate build step: the apply's docker_build_push provisioner builds and pushes ARM64 before the runtime resource, which depends_on it. tfvars.example prescribed apply -> build script -> apply, contradicting the build script's own header. - .gitignore covered .venv/ but not venv/, the third and last surface of a guard .dockerignore and the Terraform image-hash filter already cover. A real UV_PROJECT_ENVIRONMENT=venv sync produced 2329 committable files (30MB); it is now ignored, matching the other two. Also corrected while auditing every command, path, prerequisite and tool version in the same tree: the frontend is Vite, not Next.js; the CDK tester reads config.yaml at the example root, not infra-cdk/config.yaml; the CDK frontend deployer's floor is 3.8, not 3.11, and its usage hint named a path that does not resolve from the example root; build-and-push-image.sh resolves region from AWS_REGION/AWS_DEFAULT_REGION/aws-config with no us-east-1 fallback; up.sh overwrites the STACK_NAME and MEMORY_ID that .env.example told you to fill in; and backend_pattern's "available patterns" listed two agents this example does not ship. Deliberately untouched, tracked elsewhere: the missing docs/ directory and its links, "Node.js 18+", the duplicated `cd infra-cdk` teardown, the Memory-and-Gateway-only claim, the undeclared aws_region variable (still the one remaining README/tfvars.example disagreement), the absent teardown section, the duplicate deploy-frontend.sh, and every code-behaviour defect in the scripts. Verified: py_compile on all four touched Python files, bash -n on all five shell scripts, and every documented command run from the directory its text names. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
db88826432 | chore: rename Enterprise Intelligence product copy | ||
|
|
7ed7194077 |
docs(agentcore): reconcile deploy-frontend self-doc with the Terraform README
Two concurrent fixes landed different answers for the same command. The README fix measured that this script's import closure is standard-library only and that `--no-project` runs it without creating an example-root virtualenv; the self-documentation fix independently settled on `--project ..`, which also works but syncs 13 packages the script never imports. Take the README's form in both places. The point of the finding was that the two must not disagree, so leaving them on different invocations would have reproduced the defect. Verified: `--help` renders the new epilog, and the command strings in infra-terraform/README.md and scripts/deploy-frontend.py are now identical. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
54ed0464ac |
docs(agentcore): stop the uv comment claiming the runtime env vars
The comment "Configure UV for container environment" sat above a six-variable
ENV block, but only three of those are uv settings. The other three are read by
completely unrelated consumers, and the comment silently claimed them:
UV_COMPILE_BYTECODE / UV_LINK_MODE / UV_NO_CACHE uv (confirmed via `uv help
sync`, which lists all three as `[env: ...]` on uv 0.9.30)
DOCKER_CONTAINER=1 bedrock_agentcore runtime
OTEL_PYTHON_LOG_CORRELATION=true opentelemetry logging
instrumentation
PYTHONUNBUFFERED=1 the CPython interpreter
DOCKER_CONTAINER is the dangerous one. In the installed tree it has two
consumers, not one:
.venv/lib/python3.13/site-packages/bedrock_agentcore/runtime/app.py:402
if os.path.exists("/.dockerenv") or os.environ.get("DOCKER_CONTAINER"):
host = "0.0.0.0" # nosec B104 - Docker needs this to expose the port
else:
host = "127.0.0.1"
.venv/lib/python3.13/site-packages/bedrock_agentcore/identity/auth.py:163
if os.getenv("DOCKER_CONTAINER") == "1":
raise ValueError("Workload access token has not been set. ...")
(Line numbers are from the langgraph image, bedrock-agentcore 1.0.6. The strands
image pins 1.2.0, where the same two checks live at app.py:450 and auth.py:284.)
Both agents reach that first path: each builds a BedrockAgentCoreApp and calls
app.run().
The hazard: a reader who trusts the header and prunes "uv config" they don't
recognise unbinds the agent from 0.0.0.0, and nothing tells them. The bind check
is an `or` against /.dockerenv, which plain `docker run` creates -- so a local
smoke test still passes. AgentCore's managed runtime has no /.dockerenv, so the
breakage appears only once deployed. The HEALTHCHECK cannot catch it either: it
reaches the server over localhost from inside the container, which a
127.0.0.1-bound server answers happily.
Split the block into three ENV instructions, each under a comment describing
what actually reads those variables, so no variable's purpose is misattributed.
Two more instances of the same pattern, fixed in both files:
- "Create non-root user" also covered the USER line beneath it, which switches
to that user rather than creating it.
- The strands file said "Copy agent code and shared utilities" above three
COPYs, one of which is tools/. Now matches its langgraph twin.
This is comment-only. No environment variable, value, or ordering changed.
Verification, both images built for linux/arm64 from context
examples/integrations/agentcore:
- `docker run --rm --platform linux/arm64 -e GATEWAY_CREDENTIAL_PROVIDER_NAME=dummy
-e AWS_DEFAULT_REGION=us-east-1 <tag> sh -c 'env | sort'` before vs after is
identical for both agents (modulo the per-container HOSTNAME).
- `docker inspect -f '{{range .Config.Env}}...'` before vs after is identical
for both agents including ordering, so the baked config is unchanged, not
merely equivalent at runtime.
- The DOCKER_CONTAINER claim was reproduced against the real code path with
/.dockerenv masked and uvicorn.run stubbed: set -> host 0.0.0.0, unset ->
host 127.0.0.1.
- The HEALTHCHECK command was run against a 127.0.0.1-bound server inside the
container and passed, confirming the failure mode is silent.
- The two Dockerfiles are byte-identical modulo the agent name.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
484db5c8df |
fix(agentcore): finish the patterns->agents rename in the build script's error path
The `patterns/` -> `agents/` rename in build-and-push-image.sh landed on the
Dockerfile path, the `ls` target and the "Available agents:" label, but left
the `||` fallback on the same `ls` saying "No patterns found". When the agent
directory is missing entirely, the user saw a header and a body that named two
different directories:
Available agents:
No patterns found
Now both say "agents".
Deliberately NOT renamed, because they are established interface names rather
than directory vocabulary:
- the `-p, --pattern` CLI flag, its `case` arm, its help text in both the
header comment and usage(), and the `PATTERN` variable it populates;
- the "Pattern:" line in the config banner, which echoes that flag's value;
- the `backend_pattern` Terraform variable this flag mirrors, which is
declared in variables.tf and consumed across modules/backend.
Verified by running, not reading:
- `bash -n` clean before and after.
- Drove the real script to the missing-Dockerfile branch with a nonexistent
`-p does-not-exist`, an explicit `-s`/`-r`, and a local stub `aws` on PATH
that answers `sts get-caller-identity` with a dummy account id. No AWS API
was contacted and no real credentials were used.
- To fire the `||` arm itself, ran the same script from a copied tree with no
`agents/` directory. Before: "Available agents:" / " No patterns found".
After: "Available agents:" / " No agents found".
- Re-ran against the real repo tree, where `ls` succeeds and lists
langgraph-single-agent and strands-single-agent, confirming the success
path is unaffected.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
baa747eb4a |
docs(agentcore): migrate deploy-frontend.py self-documentation to uv
The Terraform frontend deploy script still told the reader to run `python scripts/deploy-frontend.py`, in both its module docstring Usage block and its argparse epilog. That contradicted two things the example had already moved on from: - infra-terraform/README.md documents `uv run --project .. scripts/deploy-frontend.py`, and - the sibling infra-terraform/scripts/test-agent.py had already had its usage text migrated to `uv run --project .. scripts/test-agent.py`. The whole agentcore example moved to uv; this one file's self-documentation did not. Aligned it with the README and the sibling rather than inventing a third convention. Also corrected the stale prerequisite line, which is the same bug pattern. It named "Python 3.8+" and no uv. Walking the full import closure confirms this script imports only the standard library (argparse, atexit, json, os, re, shutil, subprocess, sys, time, pathlib, typing) -- it pulls in none of the example-root deps and does not import scripts/utils.py -- so the "no external dependencies" fact is preserved in the new wording. But the documented invocation now goes through the example-root pyproject.toml, whose tooling project pins `requires-python >= 3.12`, so advertising a 3.8 floor for the documented command was wrong. The in-file `sys.version_info < (3, 8)` guard is left alone as the direct-interpreter safety net. Verified by running, not reading, from examples/integrations/agentcore/ infra-terraform: - `uv run --project .. scripts/deploy-frontend.py --help` renders the new epilog. - `uv run --project .. scripts/deploy-frontend.py` reaches the script and stops at "terraform is not installed" (the prerequisite loop). - With a no-op terraform stub on PATH and every AWS credential source removed, it gets past prerequisites and stops at "AWS credentials not configured or invalid". No AWS API was called -- credential lookup failed locally. No real credentials were used at any point. - `python3 -m py_compile` on the file passes. Confirmed empirically that `--project ..` does not change the working directory, so the relative `scripts/...` path in the new text resolves from infra-terraform/; the interpreter uv provisions is 3.13.2, which satisfies the >= 3.12 floor. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f69990b437 |
docs(agentcore): fix false uv dependency claims in Terraform README
The infra-terraform README justified `uv run --project .. scripts/deploy-frontend.py` with "The Python dependencies live in the example-root pyproject.toml". Both halves of that were wrong, and the command did needless work. What was false: 1. `infra-terraform/scripts/deploy-frontend.py` has no third-party dependencies. Its full import closure is argparse, atexit, json, os, re, shutil, subprocess, sys, time, pathlib and typing — all standard library, and it imports no local module. It never touches boto3/requests/PyYAML/colorama from the example-root `pyproject.toml`. 2. `--project ..` was not what made the root project reachable. `uv` already discovers `examples/integrations/agentcore/pyproject.toml` by walking up from `infra-terraform/` (it is the only pyproject.toml on that walk-up path), so the flag was redundant even for scripts that do need those packages. What it did add was a forced sync of the example-root `.venv` — 13 packages — before a script that imports none of them. The documented invocation is now `uv run --no-project scripts/deploy-frontend.py`, with plain `python3 scripts/deploy-frontend.py` noted as equally fine. The sibling `scripts/test-agent.py` genuinely differs — it imports boto3, requests and colorama — so it is documented separately as plain `uv run` (no `--no-project`, and no `--project ..` either), and the README now says so rather than making the two scripts falsely uniform. Verified by running, from `infra-terraform/`, with no AWS API calls: - `uv run --project .. scripts/deploy-frontend.py --help` (old form) printed "Creating virtual environment at: .../agentcore/.venv" and "Installed 13 packages", then ran .../agentcore/infra-terraform/scripts/deploy-frontend.py. - `uv run scripts/deploy-frontend.py --help` (no flag) produced the identical venv creation, the identical 13-package install and the identical resolved script path, confirming `--project ..` is a no-op for discovery. - `uv run --no-project scripts/deploy-frontend.py --help` (new form) resolved the same absolute script path and left no `.venv` at the example root at all. - `python3 scripts/deploy-frontend.py --help` likewise ran clean with no sync. - `uv run --no-project` on `scripts/test-agent.py` fails at `test-agent.py line 36, in <module> import boto3` (ModuleNotFoundError), while plain `uv run` syncs the 13 root packages and resolves its imports — which is why the two scripts are documented differently. Resolved script paths were captured with a runpy probe run under the very same `uv run` invocation form, using a non-`__main__` run name so module-level imports execute but `main()` does not. Audited the rest of the file for the same class of checkable-and-false claim. The remaining assertions hold: `amplify_app_id` and `amplify_staging_bucket` are real outputs in `outputs.tf`; the example-root `scripts/deploy-frontend.py` does use `aws cloudformation describe-stacks` and does take a stack name via `sys.argv[1]`; `stack_name_base` and `backend_pattern` are declared in `variables.tf`; and `--pattern` does override the `backend_pattern` value parsed from `terraform.tfvars`. Separately-tracked gaps (undeclared `aws_region`, missing `admin_user_email`, absent teardown section, undocumented `build-and-push-image.sh` and duplicate `scripts/deploy-frontend.sh`) are left untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
6db61abbc8 |
fix(agentcore): exclude non-dotted venv/ from the docker build context
`.dockerignore` excluded `**/.venv/` only, while its counterpart —
`venv_path_regex = "(^|/)\.?venv/"` in
infra-terraform/modules/backend/runtime.tf — deliberately covers BOTH
`.venv/` and `venv/`, the layout `uv sync` produces under a non-default
`UV_PROJECT_ENVIRONMENT=venv`. The two halves of the same guard disagreed,
and the comment above that local justified itself by claiming
`.dockerignore` already excluded the tree — which was false for `venv/`.
Consequence: with `UV_PROJECT_ENVIRONMENT=venv`, the virtualenv tree
entered the docker build context that feeds both Terraform's
`docker build` and the CDK `DockerImageAsset` hash in
infra-cdk/lib/backend-stack.ts, while Terraform's own content hash
ignored it. Compose Watch (docker/docker-compose.yml `agent` service,
context `..`) inherits the same rules.
Auditing the rest of the file surfaced the same
narrower-than-what-it-guards pattern in the CDK output rules:
`cdk.out*/` and `infra-cdk/cdk.out*/` are path-anchored, so a `cdk.out`
directory anywhere else was not excluded. Replaced both with
`**/cdk.out*/`. The path-anchored `infra-cdk/node_modules/` and
`frontend/node_modules/` lines were already subsumed by the
`**/node_modules/` line below them and were dropped for the same reason.
Deliberately NOT touched here (separate tracked finding): `.terraform/`,
`docker/.env`, `config.yaml`, `terraform.tfvars`, `*.tfstate`,
`aws-exports.json`, `.git/`, `frontend/dist`.
Verified by measurement, not by reading. Marker files were planted in
`venv/`, `.venv/`, `cdk.out/`, `cdk.out-lg/`, `infra-cdk/cdk.out/`,
`frontend/cdk.out/`, three `node_modules/` locations and
`__pycache__/`, at root, agent-package and deep-nested depths. A
throwaway `FROM busybox / COPY . /ctx` image then listed the real build
context.
before: 148 files in context, 5 of them leaked —
agents/langgraph-single-agent/venv/CTXPROBE.txt
agents/langgraph-single-agent/venv/CTXPROBE_mod.py
agents/strands-single-agent/venv/lib/python3.13/site-packages/pkg/CTXPROBE.txt
frontend/cdk.out/CTXPROBE.txt
venv/CTXPROBE.txt
after: 143 files in context, zero leaked; `comm` over the two
listings shows those 5 paths as the only difference and no
project file dropped.
`**/.venv/` still works after the edit: the root and agent-package
`.venv` markers are absent from both listings, and the after-listing
contains no `.venv/`, `venv/`, `node_modules`, `cdk.out`, `__pycache__`
or `*.pyc` path at all. The `**/` prefix was confirmed to match zero
path segments (root-level `.venv/` was excluded by `**/.venv/` before
the change), which is what makes `**/cdk.out*/` a strict superset of
the two anchored rules it replaces. All scratch directories were
removed; `git status` is clean apart from this commit.
The runtime.tf comment was re-worded to name both patterns so it is
true again; the filter logic itself is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
f158b81cca |
docs(agentcore): scope the langgraph version-parity comment
The comment sat above the langgraph/langchain pins but read as a claim that the whole dependency set tracks examples/integrations/langgraph-python. It does not — copilotkit and ag-ui-protocol are both behind that example. Say which pair the statement covers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
b689feed88 |
docs(agentcore): fix the Terraform frontend-deploy command in infra-terraform README
The Usage section documented a frontend deploy that could not work after a
`terraform apply`. Three defects compounded:
- The bash block ran `cd infra-terraform` and never returned, then the prose
claimed the next command ran "from the repo root" — stated cwd and actual
cwd disagreed.
- There are two `deploy-frontend.py` files. The example-root one is the CDK
variant: it reads stack outputs via `aws cloudformation describe-stacks`.
The Terraform deployment's outputs live in `terraform output -json`, which
only `infra-terraform/scripts/deploy-frontend.py` reads. Followed literally
from the repo/example root, `uv run scripts/deploy-frontend.py` executed the
CDK script.
- The CDK script also requires a stack-name argument (`sys.argv[1]`, or
`STACK_NAME`, or `infra-cdk/config.yaml` — which does not exist in this
example), and the documented invocation passed none. The deploy shell
scripts do pass it; the README did not.
The command is now `uv run --project .. scripts/deploy-frontend.py`, run from
`infra-terraform/`. `--project ..` resolves the example-root `pyproject.toml`
that owns the tooling dependencies, matching the convention already used in
`infra-terraform/scripts/test-agent.py`. The starting cwd for the whole
section is now stated, and the optional `--pattern` override (the only
argument this script accepts) is documented.
Verification, from `examples/integrations/agentcore/`:
# uv resolves the example-root project and does not change cwd
$ cd infra-terraform && uv run --project .. python -c "import os,sys; \
print(os.getcwd()); print(sys.prefix)"
.../agentcore/infra-terraform
.../agentcore/.venv
# which file each command actually executes (path + sha256 printed by a
# sitecustomize probe that exits before the script body — no AWS calls)
old, from example root: .../agentcore/scripts/deploy-frontend.py
sha256 1c3ed4f2… "…script for FAST." (CDK)
new, from infra-terraform: .../infra-terraform/scripts/deploy-frontend.py
sha256 16d3bc3c… "…for Terraform deployments."
# argument signature, real runs (terraform binary absent here, so the run
# stops at the prerequisite check before any AWS call)
$ uv run --project .. scripts/deploy-frontend.py -> exit 1, "terraform is not installed"
$ uv run --project .. scripts/deploy-frontend.py --pattern langgraph-single-agent
-> exit 1, same prereq stop
$ uv run --project .. scripts/deploy-frontend.py some-stack-name
-> exit 2, "unrecognized arguments"
The last case confirms the stack-name positional belongs to the CDK script
only. `--help` on the resolved script prints "Deploy frontend to AWS Amplify
using Terraform outputs". No AWS credentials were used and no AWS API was
called.
The known `aws_region` variable issue and the missing teardown section are
tracked separately and are untouched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
9a73e02e87 |
fix(agentcore): stop test-agent deadlocking on the local agent's pipes
start_local_agent() launched the agent with stdout=PIPE and stderr=PIPE and then never read either pipe. The child blocks the moment it fills a ~64KB pipe buffer, so a chatty agent wedges before it can bind port 8080. Worse, the 30-second startup-timeout branch called _agent_process.stderr.read() -- a blocking read to EOF -- on a child that was still alive, so the tester hung forever instead of reporting the timeout. This mattered more since the command became `uv run --locked --project ...`: uv writes resolution and install progress to stderr before the agent starts, and the message uv prints when uv.lock has drifted from pyproject.toml only reached the developer through that same wedged branch. Fix: do not pipe the child at all. stdout/stderr are inherited, so agent logs and uv's errors stream straight to the developer's terminal (this is an interactive tool), the child can never block on a full pipe, and no reader threads are needed. The wait loop now also polls the child each second and fails fast with its exit code when it dies early, instead of burning the full 30 seconds. The timeout branch delegates cleanup to stop_local_agent(), which is now idempotent (clears the global first) so the timeout path, the SIGINT handler and the atexit hook cannot double-stop or double-print, and kill() is followed by wait() so the process is reaped. Verification (standalone reproductions; this file has no test suite): - Old code vs a child writing 8000 lines and staying alive: the child never finished writing (deadlocked on a full pipe) and the parent hung in stderr.read() until an external timeout killed it (exit 124). - New code, real start_local_agent() driven against the same child: the child wrote all 8000 lines, the parent hit its timeout, stopped the agent and exited 1 after 30.1s. - Real uv project with a stale uv.lock: the developer sees "error: The lockfile at `uv.lock` needs to be updated, but `--locked` was provided." live on the terminal, and the tester reports "Agent exited with code 2 before port 8080 opened" after 1.0s. - python3 -m py_compile passes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
0a2a7737c7 |
fix(examples): declare agentcore's directly-imported deps
Several packages that agentcore code imports at module scope were never
declared in the pyproject.toml of the project that ships them. They only
resolved because something else happened to pull them in, so the next
`uv lock` that drops the intermediate would silently remove them.
That is newly dangerous: both agent Dockerfiles now install with
`uv sync --locked`, so the installed set is exactly the lockfile rather
than whatever pip incidentally resolved. A dropped transitive would turn
into an ImportError at container start instead of a quiet near-miss.
Undeclared but directly imported:
- boto3 — `agents/utils/ssm.py:12`. `agents/utils/` is COPY'd into BOTH
agent images, so both agent projects need it; neither declared it.
- PyJWT — `agents/utils/auth.py:11`. strands declared it, langgraph did
not and resolved it transitively only. langgraph now matches strands
(`PyJWT[crypto]>=2.10.1`) since it is the same shared module.
- langchain-core — `tools/todos.py:10` imports `langchain_core.messages`
in the langgraph agent; it rode in on `langchain`.
- botocore — `scripts/utils.py:17` imports `botocore.exceptions`; the
example-root project declared boto3 but not botocore.
Floors are set at or below what the existing lockfiles already resolve,
so nothing is bumped. The lock diffs are additive metadata only: zero
resolved versions changed and no new packages entered any lock.
Deliberately not declared: `docker/resolve-env.py` (boto3, PyYAML) is
already covered by the root project; `infra-cdk/lambdas/oauth2-provider/`
uses boto3 from the Lambda runtime and is bundled by CDK, not by any of
these three uv projects.
Verification (run, not read):
$ docker build --platform linux/arm64 \
-f agents/langgraph-single-agent/Dockerfile -t acuv-lg-a2:test .
naming to docker.io/library/acuv-lg-a2:test done
$ docker build --platform linux/arm64 \
-f agents/strands-single-agent/Dockerfile -t acuv-st-a2:test .
naming to docker.io/library/acuv-st-a2:test done
$ docker run --rm --platform linux/arm64 \
-e GATEWAY_CREDENTIAL_PROVIDER_NAME=dummy -e AWS_DEFAULT_REGION=us-east-1 \
acuv-lg-a2:test sh -c 'python -c "import langgraph_agent, boto3, jwt, langchain_core, utils.ssm, utils.auth, tools; ..."'
OK lg 1.43.78 2.13.0 1.6.0
$ docker run --rm --platform linux/arm64 ... acuv-st-a2:test \
sh -c 'python -c "import strands_agent, boto3, jwt, utils.ssm, utils.auth, tools; ..."'
OK st 1.43.78 2.13.0
$ uv run --locked scripts/test-agent.py --help # exit 0, usage printed
$ uv lock --check # passes for all three projects (14 / 144 / 123 packages)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
6f49df5cb3 |
fix(agentcore): exclude uv virtualenvs from the docker image content hash
terraform_data.docker_image_hash hashed every `**/*.py` under `local.pattern_dir`. Since the example moved to per-agent uv projects, that directory grows a `.venv/` the moment a developer runs `uv sync` or the local agent tester, and the virtualenv's dependency sources were being folded into the hash. That hash feeds null_resource.docker_build_push.triggers and the runtime's replace_triggered_by, so a developer who has ever run the agent locally got a spurious image rebuild plus a forced AgentCore runtime replacement, and two developers produced different plans from identical committed sources. The virtualenv never reaches the image anyway — .dockerignore excludes `**/.venv/` — so it must not reach the image hash either. fileset() has no exclude argument, so both comprehensions (pattern dir and shared utils dir) now filter on local.venv_path_regex, `(^|/)\.?venv/`, which drops `.venv/` and `venv/` at any depth while keeping files that merely start or end with those characters (`tools/venv_helpers.py`, `myvenv/x.py`). Verified by measurement, not by reading — Terraform is not installed, so the expression was reproduced exactly (fileset `**/*.py` including dot-directories, lexicographic set order, sha256 over the joined filesha256 digests) and evaluated against two worktrees holding byte-identical agent sources, one with a real 167 MB `.venv` present and one without: OLD with .venv: fileset 3114, hashed 3114 -> 5f9a98ef... OLD without: fileset 5, hashed 5 -> bacab1e1... (DIFFER) NEW with .venv: fileset 3114, hashed 5 -> bacab1e1... NEW without: fileset 5, hashed 5 -> bacab1e1... (IDENTICAL) The two OLD digests reproduce the reported values exactly, and the NEW value equals the clean-checkout digest, so the fix introduces no new hash and therefore no replacement for existing state. All 3109 dropped paths were under `.venv/`; the 5 kept are the real agent sources. A synthetic fixture additionally confirmed the shared-utils comprehension and the non-dot `venv/` (UV_PROJECT_ENVIRONMENT) variant are covered. Audit: these were the only fileset/filesha256 expressions in runtime.tf. The known undeclared-resource references in this file are untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
4a2b1a3a6e |
fix(examples): type the react-router lab's error handler and drop an undeclared import
Two type errors the example could not see. It has no check-types target, and the import is type-only, so esbuild erases it and the build passes. - `CopilotKitCoreFriendsAccess` came from `@copilotkit/core`, which the example does not depend on. `react-core/v2` re-exports it. - `onError` also accepts React's DOM error handler, so the parameter is a union and reading `.error` / `.context` off it is not allowed. Narrow on the CopilotKit shape first; a synthetic DOM event has nothing to report. Example type errors go from 9 to 3. The three left are older: two react -router codegen paths and one model name. |
||
|
|
bd1b3979f0 |
docs(examples): document uv as the agentcore Python toolchain
Prerequisites listed "Python 3.8+", which no longer matches anything: the agents require 3.13 and uv provisions the interpreter, so uv is the only thing a reader needs to install. Adds a short section on where dependencies live and the obligation to commit uv.lock, and updates the Terraform README's frontend deploy command to match. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f12c63c7fe |
fix(examples): point agentcore Terraform at the real agent paths
The Terraform docker-mode image hash read `patterns/<pattern>/requirements.txt`, `patterns/utils`, a root-level `gateway/` and `tools/`, and a root `pyproject.toml` — none of which exist in this example. `filesha256` on a missing file is a plan-time error, so docker mode could not plan at all, and the same `patterns/` prefix was baked into the build command and the standalone build-and-push script. Point them at `agents/<pattern>` and `agents/utils`, and hash the agent's `pyproject.toml` and `uv.lock` now that the dependency set is locked, so a dependency bump retriggers the image build. Zip mode is left alone; it references a `basic_agent.py` entry point and a `lambdas/zip-packager` directory that are also absent, which is a separate problem from the uv conversion. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
4534b807ec |
chore(examples): run agentcore helper scripts through uv
The deploy and local-dev scripts called bare `python3` and relied on the caller already having PyYAML, requests, boto3 and colorama importable. `scripts/requirements.txt` listed them but nothing installed it, and `uv run scripts/test-agent.py` — the command the script's own docstring gives — failed because there was no project for uv to resolve against. Route every Python entry point through `uv run --project`, backed by the example-root project added in the previous commit, and drop the orphaned `requirements.txt`. Preflight now checks for `uv` rather than `python3`; uv provisions the interpreter itself, so the hand-rolled Python 3.8 version assert goes away with it. `test-agent.py` starts a local agent inside that agent's own uv project with `--locked`, so a locally run agent gets the same dependency set as its image instead of an ad-hoc resolve. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
53f34e8cdf |
chore(examples): lock agentcore agent deps with uv projects
Both AgentCore agents installed from an unlocked `requirements.txt`, so every image build re-resolved transitive dependencies from scratch. That had already drifted into a broken state: `langgraph==1.0.10rc1` pulled in a langgraph-prebuilt that reads `ExecutionInfo` off `langgraph.runtime`, which 1.0.x does not export, so `import langgraph_agent` failed at container start. Give each agent a `pyproject.toml` + `uv.lock` and install with `uv sync --locked`, matching how every other Python integration example is set up. Bump langgraph to 1.1.6 and pin langchain to 1.2.15 — the pair used by examples/integrations/langgraph-python — to resolve the import failure, and fold the separately installed `aws-opentelemetry-distro` into the locked dependency set so it is pinned too. The example root also gains a `pyproject.toml` + `uv.lock` for the `scripts/` helpers, whose dependencies were previously declared in a `requirements.txt` that nothing installed. Verified by building both images for linux/arm64 and importing the agent module inside each container. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |