Skip to content

Conversation

@saschabuehrle
Copy link
Contributor

Summary

Validates and tests LCEL (LangChain Expression Language) composition with cascade. This is Milestone 1.5 of the LangChain integration plan. Cascade works seamlessly with pipes, sequences, batch processing, and all LCEL patterns.

Features

Already Implemented (M1.1)

Thanks to the Proxy-based delegation pattern, cascade inherits all Runnable methods from BaseChatModel:

  • .pipe(): Chain cascade with other runnables
  • .batch(): Process multiple inputs
  • .stream(): Streaming support (enhanced in M1.3)
  • RunnableSequence compatibility: Works in sequences
  • RunnablePassthrough compatibility: Works with passthrough patterns

Test Coverage

Added 15 comprehensive LCEL tests:

Test Category Count Coverage
Pipe Operator 3 Simple chains, prompt→cascade→parser, metadata preservation
RunnableSequence 2 from() method, complex sequences
Batch Processing 3 batch() method, metadata tracking, chain batching
RunnablePassthrough 1 assign() pattern
Method Chaining with LCEL 2 bind+pipe, bindTools+pipe
Stream in LCEL Chains 1 Streaming through pipes
Complex Chain Patterns 2 Branching, nested chains
Error Handling 1 Error propagation

All 15 tests passing ✅

Examples

Added examples/lcel-chains.ts demonstrating:

  1. Simple pipe chain (cascade | parser)
  2. Prompt → Cascade → Parser pattern
  3. RunnableSequence.from() usage
  4. Batch processing
  5. RunnablePassthrough.assign() branching
  6. Streaming in LCEL chains
  7. Nested chain composition
  8. Method chaining (.bind() + .pipe())

Key Capabilities

// Pipe operator
const chain = cascade.pipe(new StringOutputParser());
const result = await chain.invoke('Question?');

// Prompt → Cascade → Parser
const chain2 = prompt.pipe(cascade).pipe(parser);

// RunnableSequence
const chain3 = RunnableSequence.from([
  prompt,
  cascade,
  parser,
]);

// Batch processing
const results = await chain.batch(['Q1?', 'Q2?', 'Q3?']);

// Streaming through chain
const stream = await chain.stream('Question?');
for await (const chunk of stream) {
  console.log(chunk);
}

// Complex branching
const chain4 = RunnablePassthrough.assign({
  answer: cascade.pipe(parser),
  context: () => 'metadata',
});

Benefits

  • Full LCEL Compatibility: Works with all LCEL patterns
  • Seamless Integration: Drop-in replacement for ChatModel in chains
  • Metadata Preservation: Cascade metadata accessible via getLastCascadeResult()
  • Composition Friendly: Chains with prompts, parsers, other runnables
  • Batch & Stream: Efficient processing of multiple inputs

Test Results

Total Tests: 117 (was 102) → +15% coverage

All tests passing:

  • ✅ 28 utils tests
  • ✅ 13 helpers tests
  • ✅ 21 wrapper tests
  • ✅ 20 tool calling tests
  • ✅ 20 streaming tests
  • ✅ 15 LCEL tests

Commits

  1. a2b06f7 - test(langchain): add comprehensive LCEL composition tests (15 tests)
  2. 3bc1802 - docs(langchain): add LCEL chains example

Implementation Note

No new code was needed for M1.5! The Proxy-based delegation pattern implemented in M1.1 already provides full LCEL compatibility through inheritance from BaseChatModel. This milestone focused on validation and testing to ensure all LCEL patterns work correctly with cascade.

Next Steps

After merging to feat/langchain-integration:

  • M1.6: Package & Examples (final polish, README, publish)

Validates LCEL (LangChain Expression Language) compatibility:

Pipe Operator (3 tests):
- Simple pipe chains
- Prompt | Cascade | Parser pattern
- Metadata preservation in pipe chains

RunnableSequence (2 tests):
- Work with RunnableSequence.from()
- Handle complex sequences

Batch Processing (3 tests):
- Handle batch() method
- Preserve metadata for last batch item
- Batch with chain composition

RunnablePassthrough (1 test):
- Work with RunnablePassthrough.assign()

Method Chaining with LCEL (2 tests):
- Chain .bind() before piping
- Work with .bindTools() in LCEL chain

Stream in LCEL Chains (1 test):
- Stream through LCEL chain

Complex Chain Patterns (2 tests):
- Branching with RunnablePassthrough.assign()
- Nested chains

Error Handling (1 test):
- Propagate errors through chain

All 15 tests passing. Total test count now: 117 tests.

Related to M1.5: LCEL Composition
Demonstrates LCEL composition with cascade:

Example 1: Simple Pipe Chain
- Cascade piped to output parser

Example 2: Prompt → Cascade → Parser
- Classic LCEL chain pattern

Example 3: RunnableSequence
- Sequential composition

Example 4: Batch Processing
- Process multiple inputs efficiently

Example 5: RunnablePassthrough.assign()
- Complex branching chains

Example 6: Streaming in LCEL Chain
- Real-time streaming through pipes

Example 7: Nested Chains
- Inner and outer chain composition

Example 8: Method Chaining + Pipe
- Combine .bind() with .pipe()

Shows full LCEL compatibility and integration patterns.

Related to M1.5: LCEL Composition
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants