Migrate fdm-agents from Google ADK to LangChain/LangGraph#618
Conversation
📝 WalkthroughWalkthroughMigrate fdm-agents from ChangesLangChain Migration Core
Sequence Diagram(s)sequenceDiagram
participant ComponentA
participant ComponentB
ComponentA->>ComponentB: observable interaction
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
fdm-agents/src/tools/fertilizer-planner/index.ts (1)
65-78:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd guard for missing principalId.
The tool extracts
principalIdfromconfig?.configurablebut doesn't validate it before passing togetFields. IfprincipalIdis missing (e.g., misconfiguration),getFieldswill likely throw a less descriptive error. Add an early guard similar tosearchFertilizersTool(lines 287-289).🛡️ Suggested guard
const getFarmFieldsTool = tool( async (input: any, config?: RunnableConfig) => { const principalId = config?.configurable?.principalId as PrincipalId + if (!principalId) { + return { fields: [] } + } const timeframe = { start: new Date(`${input.calendar}-01-01`), end: new Date(`${input.calendar}-12-31`),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@fdm-agents/src/tools/fertilizer-planner/index.ts` around lines 65 - 78, Missing guard for principalId in getFarmFieldsTool: add an early check that validates config?.configurable?.principalId before calling getFields. If principalId is falsy, throw or return a descriptive error (same pattern used in searchFertilizersTool) so getFields is never called with an undefined principalId. Update the getFarmFieldsTool async handler to extract principalId, perform the guard, and only then call getFields(fdm, principalId, input.b_id_farm, timeframe).
🧹 Nitpick comments (1)
fdm-agents/src/models/default.test.ts (1)
23-27: ⚡ Quick winAssert
maxOutputTokensin constructor expectations to prevent config drift.Current tests validate
apiKeyandmodelbut miss the explicit token cap added in the factory. Add it to both assertions.🧪 Proposed test update
expect(mockChatGoogleGenerativeAI).toHaveBeenCalledWith( expect.objectContaining({ apiKey: "fake-api-key", model: "gemini-3.1-pro-preview", + maxOutputTokens: 65536, }), ) @@ expect(mockChatGoogleGenerativeAI).toHaveBeenCalledWith( expect.objectContaining({ apiKey: "fake-api-key", model: "custom-model", + maxOutputTokens: 65536, }), )Also applies to: 35-39
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@fdm-agents/src/models/default.test.ts` around lines 23 - 27, Tests currently assert apiKey and model for mockChatGoogleGenerativeAI but omit the maxOutputTokens that the factory sets; update both expect.objectContaining assertions in default.test.ts to include maxOutputTokens with the exact numeric value used in the factory (i.e., add maxOutputTokens: <the exact number from the factory>) so the test verifies the token cap and prevents config drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@fdm-agents/src/agents/gerrit/agent.ts`:
- Line 16: TOOL_LIMIT_WARNING is defined using a template literal without
interpolation causing the noUnusedTemplateLiteral lint error; replace the
backticks with double quotes for the constant (export const TOOL_LIMIT_WARNING)
and ensure the string uses double quotes to match the project's quoteStyle
configuration, i.e., change the literal in agent.ts from a backticked template
to a plain double-quoted string with the same text and punctuation.
- Around line 185-197: The agent is not being given its exported identity
constants; update the createAgent call to pass the agent name and description by
adding the name: GERRIT_NAME and description: GERRIT_DESCRIPTION properties
alongside the existing model, tools, middleware, and responseFormat so that
createAgent receives these identity fields (the invocation in this file uses
createAgent, and the constants GERRIT_NAME and GERRIT_DESCRIPTION are available;
keep the rest—createDefaultModel(resolvedKey, modelName),
createFertilizerPlannerTools(fdm), dynamicSystemPromptMiddleware, and
FertilizerPlanSchema—unchanged).
- Around line 1-2: Replace usage of the deprecated isAIMessage and the
cast-heavy check by coercing each BaseMessageLike entry to a BaseMessage then
using AIMessage.isInstance: import AIMessage and coerceMessageLikeToMessage from
`@langchain/core/messages`, loop over the messages where you currently call
isAIMessage(msg as any), call coerceMessageLikeToMessage(msg) to get a
BaseMessage and then use AIMessage.isInstance(coerced) to detect assistant/AI
messages; update any type annotations that assumed instance-only checks (e.g.,
references to BaseMessageLike) to use the coerced BaseMessage for downstream
logic such as handling tool_calls.
In `@fdm-agents/src/agents/gerrit/schema.ts`:
- Around line 15-17: The field p_app_date is declared as z.string() but must be
validated as an ISO YYYY-MM-DD date; update the p_app_date schema (symbol:
p_app_date) to enforce the YYYY-MM-DD pattern instead of accepting any
string—replace the free-form string validator with a date-specific validator
(e.g., use an ISO/date-aware Zod validator or a strict regex/refine that matches
/^\d{4}-\d{2}-\d{2}$/) and include a clear .describe() or .refine() message for
invalid values so the schema rejects non-ISO dates.
In `@fdm-agents/src/index.ts`:
- Line 109: The runtime null-check on f.b_area indicates the data model allows
null/undefined for b_area, but the interface (the one declaring b_area: number)
is not nullable; update the interface that defines the type for f (the record
used in index.ts) to make b_area nullable (e.g., number | null or number |
undefined) or optional, so the type matches the check in the template string;
ensure consistency with other nullable fields such as b_soiltype_agr and
a_som_loi.
In `@fdm-app/.env.example`:
- Around line 148-150: Replace the incorrect tracing environment variable names
with the official LangSmith variable: change any occurrences of
LANGCHAIN_TRACING (and any LANGCHAIN_TRACING_V2) to LANGSMITH_TRACING in the
.env.example files referenced (update the LANGCHAIN_TRACING entry in
fdm-app/.env.example and the corresponding entry in fdm-agents/.env.example),
and ensure the surrounding comments or examples reference LangSmith tracing
consistently so the tracer activates when LANGSMITH_TRACING is set.
In `@fdm-app/app/routes/farm`.$b_id_farm.$calendar.gerrit.tsx:
- Around line 795-802: The structured output branch currently assigns parsedPlan
= structuredResponse when FertilizerPlanSchema.safeParse(structuredResponse)
fails, which can propagate malformed data; instead, when safeParse returns
!validated.success, log a warning including validation errors (from
validated.error) and fall through to the rawResult parsing path (the same path
used when structuredResponse is falsy) so the code attempts JSON extraction from
rawResult; ensure you reference FertilizerPlanSchema.safeParse, parsedPlan,
structuredResponse and rawResult when implementing the change so the
failed-validate branch does not directly assign unvalidated structuredResponse.
---
Outside diff comments:
In `@fdm-agents/src/tools/fertilizer-planner/index.ts`:
- Around line 65-78: Missing guard for principalId in getFarmFieldsTool: add an
early check that validates config?.configurable?.principalId before calling
getFields. If principalId is falsy, throw or return a descriptive error (same
pattern used in searchFertilizersTool) so getFields is never called with an
undefined principalId. Update the getFarmFieldsTool async handler to extract
principalId, perform the guard, and only then call getFields(fdm, principalId,
input.b_id_farm, timeframe).
---
Nitpick comments:
In `@fdm-agents/src/models/default.test.ts`:
- Around line 23-27: Tests currently assert apiKey and model for
mockChatGoogleGenerativeAI but omit the maxOutputTokens that the factory sets;
update both expect.objectContaining assertions in default.test.ts to include
maxOutputTokens with the exact numeric value used in the factory (i.e., add
maxOutputTokens: <the exact number from the factory>) so the test verifies the
token cap and prevents config drift.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 62ff3a10-58c8-4579-9b5b-5013b6579c81
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
.changeset/better-pants-eat.mdfdm-agents/.env.examplefdm-agents/package.jsonfdm-agents/src/agents/gerrit/agent.test.tsfdm-agents/src/agents/gerrit/agent.tsfdm-agents/src/agents/gerrit/schema.tsfdm-agents/src/index.tsfdm-agents/src/models/default.test.tsfdm-agents/src/models/default.tsfdm-agents/src/runners/one-shot.test.tsfdm-agents/src/runners/one-shot.tsfdm-agents/src/tools/fertilizer-planner/index.test.tsfdm-agents/src/tools/fertilizer-planner/index.tsfdm-app/.env.examplefdm-app/app/components/blocks/gerrit/schema.tsfdm-app/app/routes/farm.$b_id_farm.$calendar.gerrit.tsxpnpm-workspace.yaml
| import { isAIMessage } from "@langchain/core/messages" | ||
| import type { BaseMessageLike } from "@langchain/core/messages" |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
cd fdm-agents && find . -type f -name "agent.ts" | grep gerritRepository: nmi-agro/fdm
Length of output: 85
🏁 Script executed:
cat -n src/agents/gerrit/agent.ts | head -30Repository: nmi-agro/fdm
Length of output: 115
🏁 Script executed:
cat -n src/agents/gerrit/agent.ts | sed -n '140,170p'Repository: nmi-agro/fdm
Length of output: 115
🏁 Script executed:
cat -n src/agents/gerrit/agent.ts | sed -n '10,25p'Repository: nmi-agro/fdm
Length of output: 115
🏁 Script executed:
git ls-files | grep -E "agent\.ts" | grep gerritRepository: nmi-agro/fdm
Length of output: 94
🏁 Script executed:
pwd && ls -la fdm-agents/ 2>/dev/null || ls -laRepository: nmi-agro/fdm
Length of output: 821
🏁 Script executed:
cat -n fdm-agents/src/agents/gerrit/agent.ts | head -30Repository: nmi-agro/fdm
Length of output: 3801
🏁 Script executed:
cat -n fdm-agents/src/agents/gerrit/agent.ts | sed -n '140,170p'Repository: nmi-agro/fdm
Length of output: 2077
🏁 Script executed:
cat fdm-agents/package.json | grep -A 5 -B 5 "@langchain"Repository: nmi-agro/fdm
Length of output: 535
🏁 Script executed:
cd fdm-agents && npm ls `@langchain/core` 2>/dev/null || cat package-lock.json | grep -A 2 '"@langchain/core"' | head -20Repository: nmi-agro/fdm
Length of output: 183
🏁 Script executed:
web_search
LangChain `@langchain/core` BaseMessageLike AIMessage isAIMessage coerceMessageLikeToMessageRepository: nmi-agro/fdm
Length of output: 155
🌐 Web query:
LangChain JavaScript @langchain/core BaseMessageLike isAIMessage coerceMessageLikeToMessage deprecation
💡 Result:
There’s no evidence (in the official TypeScript API reference pages we found) that BaseMessageLike or isAIMessage are currently deprecated, nor that coerceMessageLikeToMessage is deprecated. What the official docs say (as of the current reference pages): - BaseMessageLike is a type alias exported from @langchain/core and its signature is shown in the reference docs. [1] - coerceMessageLikeToMessage is documented as a function with the signature coerceMessageLikeToMessage(messageLike: BaseMessageLike): BaseMessage, and the page does not label it as deprecated. [2] - BaseMessage includes deprecatedmethod markers for getType/_getType, but that’s unrelated to BaseMessageLike / isAIMessage / coerceMessageLikeToMessage. [3] Practical takeaway: - If you’re seeing deprecation warnings in your build, they may be coming from different symbols (e.g., BaseMessage.getType/_getType are deprecated), from TypeScript usage patterns, or from a version mismatch between your installed @langchain/core and the docs you’re consulting. The coerceMessageLikeToMessage page itself does not indicate deprecation. [2] If you share the exact deprecation warning text (and your @langchain/core version), I can pinpoint which symbol is actually deprecated.
Citations:
- 1: https://reference.langchain.com/javascript/langchain-core/messages/BaseMessageLike
- 2: https://reference.langchain.com/javascript/langchain-core/messages/coerceMessageLikeToMessage
- 3: https://reference.langchain.com/javascript/langchain/browser/BaseMessage
🌐 Web query:
@langchain/core AIMessage.isInstance method
💡 Result:
In @langchain/core (JavaScript/TypeScript), AIMessage has an isInstance method that is a type guard for checking whether a value is an AIMessage. - There is a dedicated type-guard function documented as AIMessage.isInstance in the LangChain reference. It “check[s] if an object is an AIMessage” and returns a TypeScript type predicate. [1] - The documented signature is: isInstance<T extends MessageStructure>(obj: BaseMessage): obj is BaseMessage<T, MessageType> & AIMessage [1] This means when you call AIMessage.isInstance(obj), TypeScript narrows obj to an AIMessage (while preserving the typed BaseMessage generics). [1] Example usage (TypeScript): const msg: BaseMessage =... if (AIMessage.isInstance(msg)) { // msg is narrowed to AIMessage here } Notes: - The AIMessage class reference also lists an isInstance method on the AIMessage class. [2] - There is a parallel isInstance type guard for AIMessageChunk as well. [3]
Citations:
- 1: https://reference.langchain.com/javascript/langchain-core/messages/AIMessage/isInstance
- 2: https://reference.langchain.com/javascript/langchain-core/messages/AIMessage
- 3: https://reference.langchain.com/javascript/langchain-core/messages/AIMessageChunk/isInstance
🌐 Web query:
LangChain JavaScript @langchain/core BaseMessageLike type definition dictionary form
💡 Result:
The BaseMessageLike type alias from @langchain/core is defined as: typescript BaseMessageLike: BaseMessage | MessageFieldWithRole | [MessageType, MessageContent] | string | type & BaseMessageFields & Record<string, unknown> | SerializedConstructor This union type allows flexible inputs for message handling in LangChain JS/TS, including full BaseMessage instances, dictionary-like objects with role (e.g., { role: "user", content: "..." }), tuples of type and content, plain strings, objects matching BaseMessageFields with extra properties, or serialized constructors.[1]
Citations:
🏁 Script executed:
cat -n fdm-agents/src/agents/gerrit/agent.ts | sed -n '170,190p'Repository: nmi-agro/fdm
Length of output: 1036
🌐 Web query:
@langchain/core isAIMessage function deprecated
💡 Result:
In @langchain/core (LangChain.js), the function isAIMessage is deprecated; the docs say you should use AIMessage.isInstance instead. [1] What to change - Old: isAIMessage(x) (deprecated) [1] - New: AIMessage.isInstance(x) [2][1] Related note (from the same docs set): AIMessage also provides a getType method and an isInstance method on the class. [2] If you paste your exact import/usage (TypeScript or JavaScript), I can rewrite it to the recommended replacement.
Citations:
- 1: https://reference.langchain.com/javascript/langchain-core/messages/isAIMessage
- 2: https://reference.langchain.com/javascript/langchain/browser/AIMessage
🏁 Script executed:
cat -n fdm-agents/src/agents/gerrit/agent.ts | sed -n '1,10p' && echo "---" && cat -n fdm-agents/src/agents/gerrit/agent.ts | sed -n '145,165p'Repository: nmi-agro/fdm
Length of output: 1289
Replace deprecated isAIMessage and fix BaseMessageLike handling.
isAIMessage is deprecated in @langchain/core; use AIMessage.isInstance instead. More importantly, the current implementation won't correctly handle valid BaseMessageLike inputs in dictionary form (e.g., { role: "assistant", content: "", tool_calls: [...] }). Since BaseMessageLike is a union type that includes plain objects, not just BaseMessage instances, the cast-heavy check with isAIMessage(msg as any) will fail to identify dictionary-form messages as AI messages. Coerce each entry to BaseMessage first using coerceMessageLikeToMessage, then use AIMessage.isInstance to check the type.
Suggested fix
-import { isAIMessage } from "@langchain/core/messages"
+import { AIMessage, coerceMessageLikeToMessage } from "@langchain/core/messages"
import type { BaseMessageLike } from "@langchain/core/messages"
@@
export function countToolRoundtrips(
messages: readonly { tool_calls?: unknown[] }[] | BaseMessageLike[],
): number {
let count = 0
- for (const msg of messages) {
- if (
- isAIMessage(msg as any) &&
- (msg as any).tool_calls &&
- (msg as any).tool_calls.length > 0
- ) {
+ for (const raw of messages) {
+ const msg = coerceMessageLikeToMessage(raw)
+ if (AIMessage.isInstance(msg) && msg.tool_calls?.length) {
count++
}
}
return count
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@fdm-agents/src/agents/gerrit/agent.ts` around lines 1 - 2, Replace usage of
the deprecated isAIMessage and the cast-heavy check by coercing each
BaseMessageLike entry to a BaseMessage then using AIMessage.isInstance: import
AIMessage and coerceMessageLikeToMessage from `@langchain/core/messages`, loop
over the messages where you currently call isAIMessage(msg as any), call
coerceMessageLikeToMessage(msg) to get a BaseMessage and then use
AIMessage.isInstance(coerced) to detect assistant/AI messages; update any type
annotations that assumed instance-only checks (e.g., references to
BaseMessageLike) to use the coerced BaseMessage for downstream logic such as
handling tool_calls.
| p_app_date: z | ||
| .string() | ||
| .describe("Application date in YYYY-MM-DD format"), |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Zod v4, is z.iso.date()the recommended schema for validatingYYYY-MM-DD strings?
💡 Result:
Yes. In Zod v4, z.iso.date is the built-in, recommended schema for validating ISO 8601 date strings in the YYYY-MM-DD format. The Zod docs state that z.iso.date validates strings in the format YYYY-MM-DD and show examples like date.parse("2020-01-01") succeeding while "2020-1-1" fails, and they also note that ISO string validators are regex/format-based rather than full date-library semantic validation (and that z.date is for validating Date instances instead). [1][2] If you need additional “date-level” semantics (e.g., min/max/range comparisons beyond the string format), Zod’s z.iso.date is string-format validation only; the docs/comments around the API indicate you should use.refine (often with a date library) for those constraints. [3]
Citations:
- 1: https://v4.zod.dev/api?id=iso-dates
- 2: https://zod.dev/api
- 3: Feature Request : Require Zod Iso Date extended functionality for min, max and range like date does. colinhacks/zod#4988
🏁 Script executed:
# Find and check Zod version in package.json
find . -name "package.json" -type f | head -5 | xargs grep -l "zod" | head -1 | xargs cat | grep -A2 -B2 '"zod"'Repository: nmi-agro/fdm
Length of output: 170
🏁 Script executed:
# Read the actual file at the specified lines
cat -n fdm-agents/src/agents/gerrit/schema.ts | sed -n '10,25p'Repository: nmi-agro/fdm
Length of output: 724
🏁 Script executed:
# Check if z.iso.date is used anywhere else in the codebase
rg "z\.iso" --type ts --type jsRepository: nmi-agro/fdm
Length of output: 38
Enforce ISO date validation for p_app_date instead of free-form string.
Line 15–17 promises YYYY-MM-DD, but z.string() accepts any text. This breaks the structured contract and can propagate invalid plan dates. Use z.iso.date() to enforce the format.
✅ Proposed fix
- p_app_date: z
- .string()
- .describe("Application date in YYYY-MM-DD format"),
+ p_app_date: z
+ .iso.date()
+ .describe("Application date in YYYY-MM-DD format"),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| p_app_date: z | |
| .string() | |
| .describe("Application date in YYYY-MM-DD format"), | |
| p_app_date: z | |
| .iso.date() | |
| .describe("Application date in YYYY-MM-DD format"), |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@fdm-agents/src/agents/gerrit/schema.ts` around lines 15 - 17, The field
p_app_date is declared as z.string() but must be validated as an ISO YYYY-MM-DD
date; update the p_app_date schema (symbol: p_app_date) to enforce the
YYYY-MM-DD pattern instead of accepting any string—replace the free-form string
validator with a date-specific validator (e.g., use an ISO/date-aware Zod
validator or a strict regex/refine that matches /^\d{4}-\d{2}-\d{2}$/) and
include a clear .describe() or .refine() message for invalid values so the
schema rejects non-ISO dates.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@fdm-app/.env.example`:
- Around line 148-150: The .env.example uses deprecated LANGCHAIN_* names;
replace LANGCHAIN_API_KEY with LANGSMITH_API_KEY and LANGCHAIN_PROJECT with
LANGSMITH_PROJECT (keeping LANGSMITH_TRACING as-is), and update any nearby
references or documentation strings that mention LANGCHAIN_API_KEY or
LANGCHAIN_PROJECT so the example and docs consistently use the official
LANGSMITH_* environment variable names.
In `@fdm-app/app/routes/farm`.$b_id_farm.$calendar.gerrit.tsx:
- Around line 720-725: The current guard checks only fieldsSummary.length === 0
which lets farms with only non-productive (buffer/nature/small-fragment) parcels
slip through; update the check to validate the filtered/eligible set instead:
compute the productive/eligible subset from fieldsSummary using the same
criteria used later (the non-productive filter), and if that productiveFields
array is empty return the same dataWithError(...) message; reference the
existing fieldsSummary variable and the dataWithError call so you replace the
initial length check with a check against the filtered productive set before
continuing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 6855d15a-f08e-48ad-9855-3e06ae35b3eb
📒 Files selected for processing (13)
fdm-agents/.env.examplefdm-agents/src/agents/gerrit/agent.test.tsfdm-agents/src/agents/gerrit/agent.tsfdm-agents/src/agents/gerrit/schema.tsfdm-agents/src/index.test.tsfdm-agents/src/index.tsfdm-agents/src/models/default.test.tsfdm-agents/src/runners/one-shot.test.tsfdm-agents/src/runners/one-shot.tsfdm-agents/src/tools/fertilizer-planner/index.tsfdm-app/.env.examplefdm-app/app/routes/farm.$b_id_farm.$calendar.gerrit.tsxfdm-calculator/src/nutrient-advice/index.ts
🚧 Files skipped from review as they are similar to previous changes (6)
- fdm-agents/src/agents/gerrit/agent.test.ts
- fdm-agents/src/agents/gerrit/schema.ts
- fdm-agents/src/models/default.test.ts
- fdm-agents/src/runners/one-shot.test.ts
- fdm-agents/src/runners/one-shot.ts
- fdm-agents/src/tools/fertilizer-planner/index.ts
| LANGSMITH_TRACING=true | ||
| LANGCHAIN_API_KEY= | ||
| LANGCHAIN_PROJECT= No newline at end of file |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
For LangChain JS/LangGraph tracing with LangSmith in 2026, what are the official env vars for enabling tracing and API auth? Is it LANGSMITH_TRACING + LANGSMITH_API_KEY, and is LANGCHAIN_API_KEY still supported or deprecated?
💡 Result:
As of May 2026, the official environment variables for enabling LangSmith tracing and API authentication in LangChain JS/LangGraph are LANGSMITH_TRACING and LANGSMITH_API_KEY [1][2][3]. To enable tracing, you should set: export LANGSMITH_TRACING=true export LANGSMITH_API_KEY= Regarding the legacy LANGCHAIN_API_KEY variable: while it is still supported as an alias for backward compatibility, it is considered deprecated [4]. You should prioritize using the LANGSMITH_* prefixed variables for all new configurations [4]. Summary of key environment variables: - LANGSMITH_TRACING: Set to true to enable automatic tracing [1][5]. - LANGSMITH_API_KEY: Used for authentication with the LangSmith platform [5][2]. - LANGSMITH_PROJECT: Optional; specifies the project name (defaults to default if unset) [1][6]. - LANGSMITH_ENDPOINT: Optional; only required if you are using a self-hosted LangSmith instance (defaults to the hosted LangSmith cloud endpoint) [5][6]. The older aliases (LANGCHAIN_API_KEY, LANGCHAIN_ENDPOINT, LANGCHAIN_WORKSPACE_ID) remain functional but are not recommended for new implementations [4].
Citations:
- 1: https://docs.langchain.com/oss/javascript/langchain/observability
- 2: https://reference.langchain.com/javascript/langsmith
- 3: https://docs.langchain.com/langsmith/create-account-api-key
- 4: https://docs.langchain.com/langsmith/profile-configuration
- 5: https://docs.langchain.com/langsmith/env-var
- 6: https://forum.langchain.com/t/how-to-enable-langsmith-tracing-in-my-project/3077
Update LangSmith environment variable names to use official LANGSMITH_ prefixes.*
Line 149 uses LANGCHAIN_API_KEY, which is a deprecated alias. The official environment variables are LANGSMITH_API_KEY (for authentication) and LANGSMITH_PROJECT (for the project name). While the legacy names remain supported for backward compatibility as of May 2026, they are not recommended for new implementations.
Suggested patch
LANGSMITH_TRACING=true
-LANGCHAIN_API_KEY=
+LANGSMITH_API_KEY=
-LANGCHAIN_PROJECT=
+LANGSMITH_PROJECT=📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| LANGSMITH_TRACING=true | |
| LANGCHAIN_API_KEY= | |
| LANGCHAIN_PROJECT= | |
| LANGSMITH_TRACING=true | |
| LANGSMITH_API_KEY= | |
| LANGSMITH_PROJECT= |
🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 149-149: [UnorderedKey] The LANGCHAIN_API_KEY key should go before the LANGSMITH_TRACING key
(UnorderedKey)
[warning] 150-150: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
[warning] 150-150: [UnorderedKey] The LANGCHAIN_PROJECT key should go before the LANGSMITH_TRACING key
(UnorderedKey)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@fdm-app/.env.example` around lines 148 - 150, The .env.example uses
deprecated LANGCHAIN_* names; replace LANGCHAIN_API_KEY with LANGSMITH_API_KEY
and LANGCHAIN_PROJECT with LANGSMITH_PROJECT (keeping LANGSMITH_TRACING as-is),
and update any nearby references or documentation strings that mention
LANGCHAIN_API_KEY or LANGCHAIN_PROJECT so the example and docs consistently use
the official LANGSMITH_* environment variable names.
| if (fieldsSummary.length === 0) { | ||
| return dataWithError( | ||
| null, | ||
| "Er zijn geen percelen gevonden voor dit bedrijf. Voeg eerst percelen toe.", | ||
| ) | ||
| } |
There was a problem hiding this comment.
Validate “eligible/productive” fields, not just total field count.
Line 720 currently checks fieldsSummary.length === 0, but the prompt later filters non-productive fields out. A farm with only buffer/nature/small-fragment fields can still pass this guard and then generate with an effectively empty productive set.
Suggested patch
- if (fieldsSummary.length === 0) {
+ const productiveFields = fieldsSummary.filter(
+ (f) =>
+ !f.b_bufferstrip &&
+ f.b_lu_croprotation !== "nature" &&
+ (f.b_area == null || f.b_area >= 0.5),
+ )
+ if (productiveFields.length === 0) {
return dataWithError(
null,
- "Er zijn geen percelen gevonden voor dit bedrijf. Voeg eerst percelen toe.",
+ "Er zijn geen productieve percelen beschikbaar voor dit bedrijf in dit jaar.",
)
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@fdm-app/app/routes/farm`.$b_id_farm.$calendar.gerrit.tsx around lines 720 -
725, The current guard checks only fieldsSummary.length === 0 which lets farms
with only non-productive (buffer/nature/small-fragment) parcels slip through;
update the check to validate the filtered/eligible set instead: compute the
productive/eligible subset from fieldsSummary using the same criteria used later
(the non-productive filter), and if that productiveFields array is empty return
the same dataWithError(...) message; reference the existing fieldsSummary
variable and the dataWithError call so you replace the initial length check with
a check against the filtered productive set before continuing.
Summary by CodeRabbit
New Features
Bug Fixes
Chores
Closes #597