Commit 496db9c
feat(ai): systemPrompts accept { content, metadata } for per-provider metadata (#575)
* chore(monorepo): tighten build/CI scope, defensive changeset ignores, bump vite
- Exclude testing/** alongside examples/** in build, build:all, test:ci, test:pr,
test:lib, test:types, test:eslint, test:build, test:coverage. Internal test
harnesses (testing/e2e, testing/panel) had build scripts but no exclude,
so they were getting built on every release pipeline.
- Add an `ignore` list to .changeset/config.json covering every in-workspace
private package. Defends against accidental publication if `"private": true`
is ever dropped from a package by mistake.
- Bump vite from ^7.2.7 to ^7.3.3 across every declaring package.json. Resolves
a transitive version skew (some dev-only plugins pull vite@7.3.x) that was
breaking typechecking of vite.config.ts files.
- Add `engines` to the root package.json: `node >=24`, `pnpm >=11.0.0`.
* chore(tsconfig): consolidate to root tsconfig.base.json and include tests
- Introduce tsconfig.base.json at the repo root with the shared compilerOptions.
Root tsconfig.json now extends it for the small set of root-level files
(scripts, config files) we still typecheck.
- Migrate every package tsconfig to extend tsconfig.base.json with a consistent
shape: only the package's unique compilerOptions overrides (outDir, rootDir
where needed, JSX runtime, framework lib) plus a uniform
`include: ["src", "tests"]` / `exclude: ["node_modules", "dist"]`.
- Drop brittle one-off patterns: per-package duplicated compilerOptions
(ai-devtools, ai-isolate-cloudflare), explicit single-test-file includes
(ai-anthropic, ai-gemini), and `**/*.config.ts` excludes that were silently
hiding test files from `tsc`.
- Config files (vite.config.ts, vitest.config.ts) are no longer in the include
set. They're typechecked at build time by vite/vitest themselves and the
cross-tool type matrix makes them brittle to check via `tsc`.
Net effect: `pnpm test:types` now actually typechecks the tests in every
package. Prior to this commit several packages were silently excluding tests
from the typecheck pipeline.
* refactor(ai-gemini): merge GeminiThinking{,Advanced}Options into one interface
The old shape kept thinking config in two separate interfaces — one with
required `includeThoughts` + optional `thinkingBudget`, the other with
`thinkingLevel` — and intersected both into ExternalTextProviderOptions.
The intersection produced a `thinkingConfig` shape where neither
`includeThoughts`+`thinkingBudget` nor `thinkingLevel` could be passed
cleanly, even though the adapter reads both at runtime
(see src/adapters/text.ts mapCommonOptionsToGemini).
Merge into a single GeminiThinkingOptions with all three fields optional.
Drop GeminiThinkingAdvancedOptions entirely. Update model-meta intersections
and the sync-provider-models template that references the type.
GeminiThinkingOptions is the only thinking type exported from
@tanstack/ai-gemini, so no public-API breakage. GeminiThinkingAdvancedOptions
was never exported.
* refactor(ai-anthropic): drop modelOptions.system escape hatch
`system` was sneaking into modelOptions via `validKeys` and getting spread
over the system block constructed from systemPrompts. That was a leaky
abstraction: it bypassed the cross-provider `systemPrompts` API and forced
users to construct Anthropic's TextBlockParam shape manually to attach
features like cache_control.
- Remove `'system'` from validKeys in adapters/text.ts. The adapter no longer
accepts a system override from modelOptions.
- Keep `system?: string | Array<TextBlockParam>` on InternalTextProviderOptions
(the adapter still constructs it internally from `options.systemPrompts`).
Mark it explicitly as internal in the JSDoc.
- Delete the test that exercised the override behaviour and prune the
`system` field + `& { system: string }` satisfies intersection from the
one other test that was using modelOptions.system.
Regression to be aware of: there is currently no public way to attach
Anthropic `cache_control` to system prompts. A follow-up will extend
`systemPrompts` to accept `{ content, metadata }` with provider-specific
metadata (cache_control for Anthropic, others later).
* fix(ai): expose Logger via the adapter-internals subpath
`Logger` was declared as an `export interface` in src/logger/types.ts but
wasn't re-exported from src/adapter-internals.ts. Provider adapter packages
consume internals only via the `@tanstack/ai/adapter-internals` subpath, so
without this re-export they couldn't reach the `Logger` type without an
ambient import that would break the encapsulation boundary.
Surfaced by the openai-base tests once `tsc` started checking tests.
* test: fix type rot and unsafe casts surfaced by typecheck standardization
Including tests in `tsc` (see the tsconfig commit) surfaced ~200 pre-existing
type errors across the test suite that had silently rotted as source types
evolved. This commit fixes them and tightens the remaining type assertions.
Patterns fixed:
- Stale model name literals (`claude-3-7-sonnet-20250219` →
`claude-3-7-sonnet`, `grok-4-0709` → `grok-4`, `chatgpt-4.0` →
`chatgpt-4o-latest`, etc.).
- EventType string literals replaced with the enum values from
`@tanstack/ai`/`@ag-ui/core` in groq/grok/openai-base/openai tests.
- Removed/renamed provider option fields (`generationConfig.*` flattened
onto top-level Gemini options; `system` removed from anthropic
modelOptions tests).
- Required fields added to mock generation result objects (`id` on
image/speech/transcription mocks, `id` + `usage` on summarize mocks)
to satisfy GenerationFetcher result types.
- `MakeInputModalitiesTypes<['text', 'image', ...]>` wrappers and
provider-typed content parts (`AnthropicTextPart`, `OpenAITextPart`,
`GeminiImagePart`, etc.) plumbed into the model-meta tests.
- `tools` array entries replaced with typed `AnyClientTool` factories
for the elevenlabs realtime tests.
- Cloudflare worker tests: 7 `as any` casts collapsed into a single
`readJson<T>` helper with one trust-boundary cast and `Extract<>` types
per response status arm.
- ai-react/ai-solid `useChat({ onToolCall })` tests: `onToolCall` is not
a public UseChatOptions field — it's set internally by ChatClient via
the `tools` array. Deleted one test of nonexistent behaviour and
removed dead `onToolCall` options from two `addToolResult` tests.
- ai-react/ai-solid `useGeneration` tests: explicit generic arguments
instead of `onResult ... as any`; `as const` on inline chunk arrays so
StreamChunk literals infer with EventType enum values intact.
- ai-svelte `create-generation` tests: EventType enum + required fields
on AGUIEvent shapes (`threadId` on RUN_STARTED/RUN_FINISHED, `message`
on RUN_ERROR).
- openai-base tests now build a real `new OpenAI({ apiKey })` and
monkey-patch a typed `MockChatCompletionCreate` / `MockResponsesCreate`
signature instead of `as unknown as OpenAI`.
Remaining `as`-style casts in the touched files: 5 total, all at trust
boundaries with justification comments (Response.json() → typed shape;
discriminated-union narrowing for the schemaless useChat branch; AGUI
RUN_ERROR carrying both spec-shape `message` and legacy `error.message`).
`@ts-expect-error` is used in one place (audio-adapter.test.ts) for the
"unsupported model name is rejected" test, replacing an `as never` cast.
No production code changes other than:
- A new export of an existing `Logger` interface (separate commit).
- The anthropic modelOptions.system removal (separate commit).
* docs(contributing): add CONTRIBUTING.md, editorconfig, vscode recommendations
- CONTRIBUTING.md covering prereqs (Node 24, pnpm 11), initial setup,
repo layout, day-to-day commands, the per-package tsconfig pattern,
where to add unit tests, the (mandatory) E2E coverage matrix,
changesets, PR flow, and how to add a new provider adapter. Documents
the known gaps: .vue/.svelte SFCs are not linted today, and build
configs are not in the `tsc` pass.
- .editorconfig with the repo's existing conventions (LF, utf-8,
2-space, final newline).
- .vscode/extensions.json recommending eslint, prettier, vitest
explorer, nx, svelte, vue, editorconfig.
The PR template already linked to a missing CONTRIBUTING.md; this fixes
that broken link.
* ci: apply automated fixes
* chore(changesets): use ts-* glob instead of listing each example explicitly
* docs: drop incorrect Node.js v24+ requirement from READMEs and CONTRIBUTING.md
* fix: scope Node version constraint to ai-isolate-node (Node >= 22 for isolated-vm)
The previous "Node 24+" claim was overreaching:
- Only `@tanstack/ai-isolate-node` (via `isolated-vm`) has a Node version
floor. Everything else in the workspace runs fine on older Node.
- `isolated-vm`'s actual `engines.node` is `>=22.0.0` (see
https://github.com/laverdet/isolated-vm/blob/main/package.json), not 24.
Changes:
- Root package.json: drop the `node: ">=24"` entry from engines (keep the
pnpm constraint). No global Node floor for development.
- packages/typescript/ai-isolate-node/package.json: bump `engines.node`
from `>=18` to `>=22` to match upstream.
- packages/typescript/ai-isolate-node/README.md: same — say `>=22`, and
add the `--no-node-snapshot` flag note for Node 20+ runtime usage.
* chore: address CodeRabbit feedback on PR #572
- package.json: relax engines.pnpm from `>=11.0.0` to `>=10.17.0` to match
CONTRIBUTING.md ("pnpm 10.17.0 or newer"). packageManager still pins
pnpm@11.1.1 for corepack users.
- packages/typescript/ai-isolate-node/README.md: rewrite the
`--no-node-snapshot` bullet so it no longer says "Node.js 20.x and later"
alongside the "Node.js >= 22" minimum stated two bullets above. The flag
is required by isolated-vm on every Node version we support.
- packages/typescript/ai-gemini/tests/model-meta.test.ts: the
"thinking models should allow thinkingConfig" type-test was asserting
`stopSequences` (a placeholder swapped in during the typecheck rot
cleanup). Restore the original intent: assert that `thinkingConfig` is
present on `GeminiChatModelProviderOptionsByName['gemini-2.5-pro']`.
- packages/typescript/ai-openai/tests/openai-adapter.test.ts: the test
passes `systemPrompts: ['Stay concise']` but never checked that it
arrived on the outbound payload. Add the missing
`instructions: 'Stay concise'` assertion (the Responses API field the
adapter writes `systemPrompts.join('\n')` into).
Skipped:
- packages/typescript/ai-vue-ui/tsconfig.json (and sibling -ui packages):
CodeRabbit suggested adding `"tests"` to `include`. The *-ui packages
have no test files on disk and use `composite: true` with `rootDir: src`,
so widening include would point at a non-existent directory.
* feat(ai): systemPrompts accept { content, metadata } with adapter-inferred metadata typing
Extends `chat({ systemPrompts })` to accept either a plain string (existing
shape — backward compatible) or `{ content, metadata }`. The structured
form's `metadata` type is inferred from the adapter at the chat() call site
via a new `TSystemPromptMetadata` generic on `TextAdapter` — no `satisfies`
needed by callers.
- Anthropic declares `AnthropicSystemPromptMetadata` → users get
`cache_control` autocomplete + type-checking.
- Adapters with no per-prompt metadata (OpenAI, Gemini, Ollama,
OpenRouter, openai-base) inherit the default `never`, which makes the
`metadata` field unusable at the call site. Passing metadata to those
adapters is a TypeScript error.
Closes the regression introduced by removing the `modelOptions.system`
escape hatch in the audit PR — there is now a public, typed path for
attaching Anthropic `cache_control` to system prompts.
Plumbing
- New `TSystemPromptMetadata = never` generic on `TextAdapter` /
`BaseTextAdapter`, surfaced via `'~types'['systemPromptMetadata']`.
`TextActivityOptions.systemPrompts` is now
`Array<SystemPrompt<TAdapter['~types']['systemPromptMetadata']>>`.
- `AnyTextAdapter` extended to 7 generic slots.
- `TextOptions.systemPrompts` (the wide internal shape adapters receive)
is `Array<SystemPrompt>`; adapters call `normalizeSystemPrompts<...>()`
to narrow.
- Chat engine + middleware context/config widened to carry
`Array<SystemPrompt>` so metadata flows through to the adapter.
- OpenTelemetry middleware extracts `.content` for span events;
per-prompt metadata is dropped from spans.
- `@tanstack/ai-event-client` mirrors the `SystemPrompt` shape locally
(avoids a circular import with `@tanstack/ai`) and projects metadata
away on the devtools wire.
Adapter mappings
- Anthropic reads `metadata.cache_control` and attaches it to the
matching `TextBlockParam`.
- OpenAI / Gemini / Ollama / OpenRouter / openai-base call
`normalizeSystemPrompts()` and join `.content` for their respective
`instructions` / `system` / `systemInstruction` fields. (Their
metadata type is `never`, so the field can't be set anyway.)
Tests
- ai-anthropic: new test verifies `cache_control` flows from
`systemPrompts[i].metadata` onto the outbound `TextBlockParam`, and
plain-string entries still produce metadata-less blocks.
- ai-openai: new test verifies mixed string + object-form input
(without metadata) produces the expected joined `instructions`.
* ci: apply automated fixes
* address PR #575 review feedback
Maps to tombeckenham's review items C1, I1–I6:
- C1 (runtime validation): `normalizeSystemPrompts` throws TypeError naming
the offending index when an object-form entry's content isn't a string,
so stale call sites can't stream a literal "undefined" into the model.
New test file `packages/typescript/ai/tests/system-prompts.test.ts`
covers the happy paths and the throw cases.
- I1 (E2E coverage): `testing/e2e/tests/system-prompt-metadata.spec.ts`
drives the full Anthropic HTTP path with object-form systemPrompts +
metadata.cache_control. Wire-shape assertion stays in the ai-anthropic
unit test (aimock's journal normalises Anthropic into an OpenAI-shaped
request and drops `cache_control`, so a journal-based assertion isn't
reliable — the spec asserts end-to-end success instead). Required a
test-only `systemPromptCacheControl` opt-in on `api.chat.ts` to flip
the system prompt to object form.
- I2 (middleware widened-shape coverage): new
`middleware.test.ts > should preserve object-form systemPrompts through
middleware` asserts the middleware sees `Array<SystemPrompt>`, not a
pre-flattened `Array<string>`, and that mutations preserve metadata
through to the adapter.
- I3 (per-adapter mapping coverage): direct unit tests for
Gemini (`systemInstruction` joined; foreign metadata dropped),
Ollama (`messages.unshift({role:'system'})` joined; foreign metadata
dropped), and OpenRouter (positional `{role:'system'}` message; foreign
metadata dropped).
- I4 (OTel metadata observability): when `captureContent: true` and at
least one entry carries metadata, the iteration span gains a
`tanstack.ai.system_prompt.metadata` JSON attribute (positional
per-prompt array, `null` for plain strings / no metadata). Kept off
span events so the existing one-event-per-message GenAI semconv stays
intact. New tests in `tests/middlewares/otel.test.ts` cover both the
set and the absent path.
- I5 (doc/changeset wording): replaced "silently ignore" with the
accurate "carries no meaningful value … silently dropped, never
written to the wire" framing in `SystemPrompt`'s JSDoc, the
`TextOptions.systemPrompts` JSDoc, and the changeset. Removed the
misleading `satisfies AnthropicSystemPromptMetadata` from the
`@example` (the adapter narrows the metadata field at the call site,
so a `satisfies` cast is contradicted by the tests).
- I6 (devtools structural guard):
`ai-event-client/tests/devtools-middleware-shape.test.ts` re-declares
the local `DevtoolsSystemPrompt` mirror and uses `expectTypeOf` to
assert mutual assignability with `@tanstack/ai`'s `SystemPrompt`. If
the canonical shape gains a third variant the guard breaks at
type-check time, forcing the maintainer to update the mirror in
`devtools-middleware.ts`.
Suggestions S1–S5 deferred per the reviewer's "follow-up acceptable" call.
* ci: apply automated fixes
* fix CI: ai-event-client cross-package import + system-prompts lint
Two CI failures on the previous review-feedback commit, both follow-ups to
the same patch:
- `@tanstack/ai-event-client:test:types` failed because the new
`devtools-middleware-shape.test.ts` imported `SystemPrompt` from
`@tanstack/ai`, but `@tanstack/ai-event-client` only declares
`@tanstack/ai` as a peerDependency. Nx's project graph therefore
doesn't see a build edge and the `^build` predecessor for test:types
never produces the dist files tsc needs. Adding a `workspace:*` devDep
would close the loop but reintroduce the circular dev/runtime dep the
current architecture is built to avoid.
Move the structural guard test into `@tanstack/ai/tests/` instead.
`@tanstack/ai` has no edge to ai-event-client's source for this
assertion (the mirror gets re-declared inline), and the test now lives
alongside the type it's guarding.
- `@tanstack/ai:test:eslint` failed on
`@typescript-eslint/no-unnecessary-condition` at the C1 runtime checks
inside `normalizeSystemPrompts`. TS narrows `p` to the object arm
after the string branch, so the `p === null || typeof p !== 'object'`
guard looks redundant to the rule even though it's deliberate
defence-in-depth at a public API boundary. Cast through `unknown`
to drop the narrow and re-validate without disabling the rule.
Same treatment for the `p.content` typeof check — read `content` off
an `unknown`-typed view of the candidate so the runtime check is
visible to the linter without an eslint-disable.
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>1 parent ed53773 commit 496db9c
33 files changed
Lines changed: 928 additions & 53 deletions
File tree
- .changeset
- packages/typescript
- ai-anthropic
- src
- adapters
- text
- tests
- ai-event-client/src
- ai-gemini
- src/adapters
- tests
- ai-ollama
- src/adapters
- tests
- ai-openai
- src/adapters
- tests
- ai-openrouter
- src/adapters
- tests
- ai
- src
- activities/chat
- middleware
- middlewares
- tests
- middlewares
- openai-base/src/adapters
- testing/e2e
- src/routes
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
41 | 42 | | |
42 | 43 | | |
43 | 44 | | |
| |||
115 | 116 | | |
116 | 117 | | |
117 | 118 | | |
118 | | - | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
119 | 125 | | |
120 | 126 | | |
121 | 127 | | |
| |||
356 | 362 | | |
357 | 363 | | |
358 | 364 | | |
359 | | - | |
360 | | - | |
361 | | - | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
362 | 369 | | |
363 | | - | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
364 | 381 | | |
365 | 382 | | |
366 | 383 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| |||
Lines changed: 31 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
13 | 44 | | |
14 | 45 | | |
15 | 46 | | |
| |||
Lines changed: 62 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
117 | 117 | | |
118 | 118 | | |
119 | 119 | | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
120 | 178 | | |
121 | 179 | | |
122 | 180 | | |
| |||
127 | 185 | | |
128 | 186 | | |
129 | 187 | | |
130 | | - | |
| 188 | + | |
131 | 189 | | |
132 | 190 | | |
133 | 191 | | |
134 | 192 | | |
135 | | - | |
| 193 | + | |
136 | 194 | | |
137 | 195 | | |
138 | 196 | | |
| |||
148 | 206 | | |
149 | 207 | | |
150 | 208 | | |
151 | | - | |
152 | | - | |
| 209 | + | |
153 | 210 | | |
154 | 211 | | |
155 | 212 | | |
| |||
159 | 216 | | |
160 | 217 | | |
161 | 218 | | |
162 | | - | |
| 219 | + | |
163 | 220 | | |
164 | 221 | | |
165 | 222 | | |
| |||
Lines changed: 15 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
15 | 22 | | |
16 | 23 | | |
17 | 24 | | |
18 | 25 | | |
19 | 26 | | |
20 | 27 | | |
21 | 28 | | |
22 | | - | |
| 29 | + | |
23 | 30 | | |
24 | 31 | | |
25 | 32 | | |
| |||
104 | 111 | | |
105 | 112 | | |
106 | 113 | | |
107 | | - | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
108 | 121 | | |
109 | 122 | | |
110 | 123 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| |||
838 | 838 | | |
839 | 839 | | |
840 | 840 | | |
841 | | - | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
842 | 847 | | |
843 | 848 | | |
844 | 849 | | |
| |||
0 commit comments