diff --git a/AGENTS.md b/AGENTS.md index 5ca91914..6c9f5591 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -71,6 +71,7 @@ scripts/ Repo tooling (run-app, cli-sandbox, release-notes) - **No gratuitous defensive code.** Don't add try/catch, null checks, or input validation the surrounding file doesn't have — especially on paths already validated upstream. Match the file's level of paranoia. - **No silent fallbacks.** No empty `catch`, no `?? default` that masks a bug, no `as any` to silence TypeScript. If something can fail, let it fail loudly or handle it explicitly. - **Comments are rare and earn their place.** Only for constraints the code can't express (a protocol quirk, a deliberate perf trade-off). Never paraphrase the code, never narrate a change. When in doubt: no comment. +- **A comment states a durable constraint, not the moment you wrote it.** One or two lines. No issue ids, no measurements, no before/after story, no "I found that…" — that belongs in the PR body, the changeset, or a doc. Code outlives the task that produced it; a paragraph pinned to last Tuesday's investigation reads as noise six months later and nobody dares delete it. - **This extends to all prose**: test names, error/log messages, changeset descriptions, PR bodies. Factual and plain — no emoji, no superlatives, no filler. - **No speculative code.** No unrequested options or parameters, no "just in case" branches, no keeping the old code path alongside the new one. Delete dead code; public API deprecations are a maintainer decision — ask first. - **Prefer deleting and simplifying over working around.** If the fix needs a workaround, question the design before adding the workaround. diff --git a/apps/evi/agent/agent.ts b/apps/evi/agent/agent.ts index 3e4676d7..271c1f13 100644 --- a/apps/evi/agent/agent.ts +++ b/apps/evi/agent/agent.ts @@ -19,9 +19,10 @@ export default defineAgent({ }), /** This model honors only `high` and `xhigh`. */ reasoning: 'high', + /** Bounds a runaway session, not cost: one real thread runs a few million in. */ limits: { - maxInputTokensPerSession: 5_000_000, - maxOutputTokensPerSession: 100_000, + maxInputTokensPerSession: 20_000_000, + maxOutputTokensPerSession: 250_000, }, modelOptions: { providerOptions: { gateway: { ...gatewayRouting, tags: sessionTags() } }, diff --git a/apps/evi/agent/connections/linear.ts b/apps/evi/agent/connections/linear.ts deleted file mode 100644 index 355517f3..00000000 --- a/apps/evi/agent/connections/linear.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { connect } from '@vercel/connect/eve' -import { defineMcpClientConnection } from 'eve/connections' - -export default defineMcpClientConnection({ - url: 'https://mcp.linear.app/mcp', - description: 'Linear workspace: issues, projects, cycles, and comments.', - auth: connect({ connector: 'mcp.linear.app/linear-mcp', principalType: 'app' }), -}) diff --git a/apps/evi/agent/lib/channel.ts b/apps/evi/agent/lib/channel.ts index eada963b..3fab9c7a 100644 --- a/apps/evi/agent/lib/channel.ts +++ b/apps/evi/agent/lib/channel.ts @@ -1,9 +1,6 @@ /** - * The channel name eve reports, without its prefix. - * - * Framework channels arrive bare (`http`, `schedule`, `subagent`); authored ones - * as `channel:`, so `agent/channels/github.ts` is `channel:github`. - * Comparing against the bare name without stripping never matches. + * The channel name eve reports, without its prefix. Framework channels arrive + * bare (`http`, `schedule`); authored ones as `channel:`. */ export function channelName(kind?: string): string { return (kind ?? 'unknown').replace(/^channel:/, '') diff --git a/apps/evi/agent/lib/environment.ts b/apps/evi/agent/lib/environment.ts index c09446a1..8e42b019 100644 --- a/apps/evi/agent/lib/environment.ts +++ b/apps/evi/agent/lib/environment.ts @@ -1,9 +1,7 @@ /** - * Where this process is running, as one label. - * - * Shared by the gateway spend tags and the evlog wide events so a run that bills - * as `eval` also logs as `eval`. `EVE_RUN_MODE` is set by the `eval` script; it - * does not reach a deployment behind `eve eval --url`. + * Where this process is running. Shared by the gateway spend tags and the evlog + * wide events so both label a run the same way. `EVE_RUN_MODE` comes from the + * `eval` script and does not reach a deployment behind `eve eval --url`. */ export function environment(): string { if (process.env.EVE_RUN_MODE === 'eval') return 'eval' diff --git a/apps/evi/agent/lib/gateway.ts b/apps/evi/agent/lib/gateway.ts index 9cd9147d..5a45218c 100644 --- a/apps/evi/agent/lib/gateway.ts +++ b/apps/evi/agent/lib/gateway.ts @@ -8,10 +8,8 @@ export const gatewayRouting = { } as const /** - * Tags stamped on every gateway request, read back through the spend report. - * - * One tag per dimension, not one compound string: the report groups by a single - * dimension at a time, so this yields a row per environment and a row per surface. + * Tags stamped on every gateway request. One tag per dimension, not a compound + * string: the spend report groups by a single dimension at a time. */ export function sessionTags(kind?: string): string[] { return [`evi:env:${environment()}`, `evi:surface:${channelName(kind)}`] diff --git a/apps/evi/docs/notes.md b/apps/evi/docs/notes.md index 4f5be3e2..ed9653c8 100644 --- a/apps/evi/docs/notes.md +++ b/apps/evi/docs/notes.md @@ -76,6 +76,15 @@ Because app-scoped is non-interactive, eve never emits a challenge: anyone can approve, on every turn. User-scoped at least fails loudly with `principal_required`. +**A misconfigured OAuth connection does not degrade, it breaks the whole run.** +On EVL-213, the Linear MCP connection took every GitHub tool down with it: five +calls, all `Cannot read properties of undefined (reading 'toLowerCase')`, thrown +from `isProvisionableConnectorUid` in +`@vercel/connect/dist/eve/provision-oauth-connector.js`. Local evals never saw it +because `provisionEveOAuthConnector` returns early without an OIDC token; in +production it runs. The connection is removed until Connect can mint the token — +assuming the agent simply answers without that connection is wrong. + **`vercel connect token` from the CLI proves nothing about app-scoped auth** — it resolves through your own Vercel identity, the user-scoped path.