JAF ADK Layer Implementation Plan¶
Overview¶
The JAF ADK Layer will provide ADK-style functionality while maintaining JAF's core functional principles. This layer will bridge the gap between ADK's rich feature set and JAF's functional purity, enabling developers to leverage ADK patterns in a functional context.
Architecture Design¶
Core Principle: Functional ADK¶
The JAF ADK Layer follows these principles: - No Classes: All ADK concepts mapped to pure functions - Immutable State: All state passed explicitly through function parameters - Composition: ADK-style patterns built through function composition - Type Safety: Full TypeScript typing throughout
Layer Structure¶
src/
├── adk/
│ ├── agents/ # Agent creation and management functions
│ ├── runners/ # Execution functions
│ ├── sessions/ # Session management functions
│ ├── tools/ # Tool integration functions
│ ├── content/ # Content and message handling
│ ├── streaming/ # Streaming and live interaction
│ ├── schemas/ # Schema validation functions
│ └── index.ts # Main exports
Functional Mapping: ADK Concepts → JAF Functions¶
1. Agent System¶
ADK Pattern:¶
agent = LlmAgent(
name="weather_agent",
model="gemini-2.0-flash",
instruction="You are a weather assistant",
tools=[weather_tool],
input_schema=WeatherQuery
)
JAF Functional Equivalent:¶
// Agent Configuration Type
interface AgentConfig {
name: string;
model: string;
instruction: string;
tools: Tool[];
inputSchema?: SchemaValidator;
outputSchema?: SchemaValidator;
subAgents?: AgentConfig[];
}
// Agent Creation Function
const createAgent = (config: AgentConfig): Agent => ({
id: generateId(),
config,
metadata: {
created: new Date(),
version: '1.0.0'
}
});
// Usage
const weatherAgent = createAgent({
name: "weather_agent",
model: "gemini-2.0-flash",
instruction: "You are a weather assistant",
tools: [weatherTool],
inputSchema: weatherQuerySchema
});
2. Runner System¶
ADK Pattern:¶
runner = Runner(agent=agent, session_service=session_service)
events = runner.run_async(user_id="123", session_id="456", new_message=content)
JAF Functional Equivalent:¶
// Runner Configuration
interface RunnerConfig {
agent: Agent;
sessionProvider: SessionProvider;
artifactProvider?: ArtifactProvider;
guardrails?: GuardrailFunction[];
}
// Single Execution Function
const runAgent = async (
config: RunnerConfig,
context: RunContext,
message: Content
): Promise<AgentResponse> => {
const session = await getOrCreateSession(config.sessionProvider, context);
const guardedMessage = await applyGuardrails(config.guardrails || [], message);
const response = await executeAgent(config.agent, session, guardedMessage);
return response;
};
// Streaming Execution Function
const runAgentStream = async function* (
config: RunnerConfig,
context: RunContext,
message: Content
): AsyncGenerator<AgentEvent> {
const session = await getOrCreateSession(config.sessionProvider, context);
const eventStream = executeAgentStream(config.agent, session, message);
for await (const event of eventStream) {
yield event;
}
};
// Usage
const response = await runAgent(runnerConfig, {
userId: "123",
sessionId: "456"
}, message);
3. Session Management¶
ADK Pattern:¶
session_service = InMemorySessionService()
session = await session_service.create_session(app_name="app", user_id="123")
JAF Functional Equivalent:¶
// Session Provider Interface
interface SessionProvider {
createSession: (context: SessionContext) => Promise<Session>;
getSession: (sessionId: string) => Promise<Session | null>;
updateSession: (session: Session) => Promise<Session>;
listSessions: (userId: string) => Promise<Session[]>;
}
// In-Memory Session Provider Factory
const createInMemorySessionProvider = (): SessionProvider => {
const sessions = new Map<string, Session>();
return {
createSession: async (context) => {
const session: Session = {
id: generateId(),
appName: context.appName,
userId: context.userId,
messages: [],
artifacts: {},
metadata: { created: new Date() }
};
sessions.set(session.id, session);
return session;
},
getSession: async (sessionId) => sessions.get(sessionId) || null,
updateSession: async (session) => {
sessions.set(session.id, session);
return session;
},
listSessions: async (userId) =>
Array.from(sessions.values()).filter(s => s.userId === userId)
};
};
// Usage
const sessionProvider = createInMemorySessionProvider();
const session = await sessionProvider.createSession({
appName: "weather_app",
userId: "123"
});
4. Tool System¶
ADK Pattern:¶
tools = [
FunctionTool(func=get_weather),
OpenAPIToolset(spec_str=api_spec),
CrewaiTool(tool=serper_tool)
]
JAF Functional Equivalent:¶
// Tool Interface
interface Tool {
name: string;
description: string;
parameters: ToolParameter[];
execute: ToolExecutor;
}
// Function Tool Factory
const createFunctionTool = (
name: string,
description: string,
func: Function,
parameters: ToolParameter[]
): Tool => ({
name,
description,
parameters,
execute: async (params, context) => {
const result = await func(params);
return { success: true, data: result };
}
});
// OpenAPI Toolset Factory
const createOpenAPIToolset = async (
spec: OpenAPISpec
): Promise<Tool[]> => {
const tools: Tool[] = [];
for (const [path, methods] of Object.entries(spec.paths)) {
for (const [method, operation] of Object.entries(methods)) {
const tool = createToolFromOperation(path, method, operation);
tools.push(tool);
}
}
return tools;
};
// CrewAI Tool Adapter
const createCrewAIToolAdapter = (crewAITool: any): Tool => ({
name: crewAITool.name,
description: crewAITool.description,
parameters: extractParameters(crewAITool),
execute: async (params, context) => {
const result = await crewAITool.run(params);
return { success: true, data: result };
}
});
// Usage
const tools = [
createFunctionTool("get_weather", "Get weather info", getWeather, weatherParams),
...(await createOpenAPIToolset(weatherAPISpec)),
createCrewAIToolAdapter(serperTool)
];
5. Schema Validation¶
ADK Pattern:¶
class WeatherQuery(BaseModel):
location: str = Field(description="City name")
units: str = Field(default="celsius")
agent = LlmAgent(input_schema=WeatherQuery)
JAF Functional Equivalent:¶
// Schema Definition
interface WeatherQuery {
location: string;
units?: 'celsius' | 'fahrenheit';
}
// Schema Validator Factory
const createSchemaValidator = <T>(
schema: JsonSchema,
validator: (data: unknown) => data is T
): SchemaValidator<T> => ({
schema,
validate: (data: unknown): ValidationResult<T> => {
if (validator(data)) {
return { success: true, data };
}
return {
success: false,
errors: ['Validation failed']
};
}
});
// Runtime Validation
const weatherQueryValidator = createSchemaValidator<WeatherQuery>(
weatherQuerySchema,
(data): data is WeatherQuery =>
typeof data === 'object' &&
data !== null &&
'location' in data &&
typeof data.location === 'string'
);
// Usage in Agent
const weatherAgent = createAgent({
name: "weather_agent",
model: "gemini-2.0-flash",
instruction: "You are a weather assistant",
tools: [weatherTool],
inputSchema: weatherQueryValidator
});
6. Multi-Agent Systems¶
ADK Pattern:¶
coordinator = LlmAgent(
name="coordinator",
sub_agents=[weather_agent, news_agent, calendar_agent]
)
JAF Functional Equivalent:¶
// Multi-Agent Configuration
interface MultiAgentConfig extends AgentConfig {
subAgents: AgentConfig[];
delegationStrategy: DelegationStrategy;
}
// Delegation Strategy
type DelegationStrategy =
| 'sequential' // Run agents in order
| 'parallel' // Run agents concurrently
| 'conditional' // Choose agent based on conditions
| 'hierarchical'; // Delegate based on capability
// Multi-Agent Execution
const runMultiAgent = async (
config: MultiAgentConfig,
context: RunContext,
message: Content
): Promise<AgentResponse> => {
const coordinator = createAgent(config);
switch (config.delegationStrategy) {
case 'sequential':
return runSequentialAgents(config.subAgents, context, message);
case 'parallel':
return runParallelAgents(config.subAgents, context, message);
case 'conditional':
return runConditionalAgents(config.subAgents, context, message);
case 'hierarchical':
return runHierarchicalAgents(config.subAgents, context, message);
}
};
// Usage
const coordinatorAgent = createAgent({
name: "coordinator",
model: "gemini-2.0-flash",
instruction: "Coordinate multiple specialized agents",
tools: [],
subAgents: [weatherAgent, newsAgent, calendarAgent],
delegationStrategy: 'conditional'
});
Implementation Phases¶
Phase 1: Core Foundation (Weeks 1-2)¶
- Basic agent creation functions
- Simple runner implementation
- In-memory session provider
- Function tool support
- Basic content types
Phase 2: Tool Ecosystem (Weeks 3-4)¶
- OpenAPI toolset generation
- External tool adapters (CrewAI, LangChain)
- MCP protocol support
- Tool composition utilities
Phase 3: Advanced Features (Weeks 5-6)¶
- Schema validation system
- Multi-agent coordination
- Guardrail functions
- Artifact management
Phase 4: Streaming & Live Features (Weeks 7-8)¶
- Streaming execution
- Live interaction queues
- Bidirectional communication
- Event system
Phase 5: Integration & Utilities (Weeks 9-10)¶
- Example system for few-shot learning
- Web UI integration
- Testing utilities
- Documentation and examples
Function Signatures Reference¶
Core Functions¶
// Agent Management
export const createAgent: (config: AgentConfig) => Agent;
export const validateAgent: (agent: Agent) => ValidationResult;
export const cloneAgent: (agent: Agent, overrides: Partial<AgentConfig>) => Agent;
// Execution
export const runAgent: (config: RunnerConfig, context: RunContext, message: Content) => Promise<AgentResponse>;
export const runAgentStream: (config: RunnerConfig, context: RunContext, message: Content) => AsyncGenerator<AgentEvent>;
export const runMultiAgent: (config: MultiAgentConfig, context: RunContext, message: Content) => Promise<AgentResponse>;
// Session Management
export const createInMemorySessionProvider: () => SessionProvider;
export const createRedisSessionProvider: (config: RedisConfig) => SessionProvider;
export const createPostgresSessionProvider: (config: PostgresConfig) => SessionProvider;
// Tool System
export const createFunctionTool: (name: string, description: string, func: Function, parameters: ToolParameter[]) => Tool;
export const createOpenAPIToolset: (spec: OpenAPISpec) => Promise<Tool[]>;
export const createCrewAIAdapter: (tool: CrewAITool) => Tool;
export const createLangChainAdapter: (tool: LangChainTool) => Tool;
// Schema Validation
export const createSchemaValidator: <T>(schema: JsonSchema, validator: TypeGuard<T>) => SchemaValidator<T>;
export const validateInput: <T>(validator: SchemaValidator<T>, data: unknown) => ValidationResult<T>;
export const validateOutput: <T>(validator: SchemaValidator<T>, data: unknown) => ValidationResult<T>;
// Content and Messaging
export const createContent: (role: 'user' | 'model', text: string) => Content;
export const createPart: (text: string, type?: PartType) => Part;
export const parseContent: (raw: string | object) => Content;
// Guardrails
export const createGuardrail: (name: string, check: GuardrailCheck) => GuardrailFunction;
export const applyGuardrails: (guardrails: GuardrailFunction[], message: Content) => Promise<Content>;
// Streaming
export const createLiveQueue: () => LiveRequestQueue;
export const streamToQueue: (stream: AsyncGenerator<AgentEvent>, queue: LiveRequestQueue) => Promise<void>;
export const queueToStream: (queue: LiveRequestQueue) => AsyncGenerator<AgentEvent>;
Integration with Existing JAF¶
Memory Provider Bridge¶
// Bridge JAF memory providers to ADK session providers
const createMemoryProviderBridge = (
memoryProvider: MemoryProvider
): SessionProvider => ({
createSession: async (context) => {
const memory = await memoryProvider.createMemory(context.userId);
return sessionFromMemory(memory, context);
},
getSession: async (sessionId) => {
const memory = await memoryProvider.getMemory(sessionId);
return memory ? sessionFromMemory(memory) : null;
},
updateSession: async (session) => {
const memory = memoryFromSession(session);
await memoryProvider.updateMemory(session.id, memory);
return session;
},
listSessions: async (userId) => {
const memories = await memoryProvider.listMemories(userId);
return memories.map(memory => sessionFromMemory(memory));
}
});
Tool Compatibility¶
// Bridge JAF tools to ADK tools
const createJAFToolBridge = (jafTool: JAFTool): Tool => ({
name: jafTool.name,
description: jafTool.description,
parameters: jafTool.parameters,
execute: async (params, context) => {
const result = await jafTool.execute(params);
return {
success: result.success,
data: result.content,
error: result.error
};
}
});
Benefits of JAF ADK Layer¶
For Developers¶
- Familiar Patterns: ADK-style APIs in functional form
- Rich Ecosystem: Access to ADK's tool integrations
- Type Safety: Full TypeScript support
- Functional Purity: No classes, immutable state
- Gradual Adoption: Can be added incrementally to existing JAF projects
For Framework¶
- Enhanced Capabilities: Multi-agent systems, streaming, guardrails
- Ecosystem Growth: Compatibility with ADK tools and patterns
- Developer Experience: Simplified complex agent workflows
- Production Ready: Battle-tested patterns from Google ADK
Success Metrics¶
Implementation Success¶
- 100% functional equivalent of core ADK features
- Zero classes in the implementation
- Full TypeScript coverage
- Performance parity with existing JAF functions
Developer Adoption¶
- Clear migration path from ADK to JAF ADK Layer
- Comprehensive documentation and examples
- Positive developer feedback
- Active usage in JAF projects
Ecosystem Integration¶
- Compatibility with major ADK tools (90%+)
- Seamless integration with existing JAF memory providers
- Support for ADK patterns (agents, tools, streaming)
- Maintained functional programming principles
Next Steps¶
- Prototype Development: Implement Phase 1 core functions
- Tool Integration: Start with most common ADK tools
- Testing Framework: Ensure compatibility and correctness
- Documentation: Create comprehensive guides and examples
- Community Feedback: Gather input from JAF and ADK developers
This JAF ADK Layer will bridge the best of both worlds - ADK's rich feature set and JAF's functional purity - creating a powerful, type-safe, and developer-friendly agent framework.