Full Code of LnYo-Cly/ai4j for AI

main a5934b569eef cached
1275 files
5.4 MB
1.5M tokens
8443 symbols
1 requests
Download .txt
Showing preview only (6,161K chars total). Download the full file or copy to clipboard to get everything.
Repository: LnYo-Cly/ai4j
Branch: main
Commit: a5934b569eef
Files: 1275
Total size: 5.4 MB

Directory structure:
gitextract_x29x44af/

├── .editorconfig
├── .github/
│   └── workflows/
│       ├── docs-build.yml
│       └── docs-pages.yml
├── .gitignore
├── LICENSE
├── README-EN.md
├── README.md
├── ai4j/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── github/
│       │   │           └── lnyocly/
│       │   │               └── ai4j/
│       │   │                   ├── agentflow/
│       │   │                   │   ├── AgentFlow.java
│       │   │                   │   ├── AgentFlowConfig.java
│       │   │                   │   ├── AgentFlowException.java
│       │   │                   │   ├── AgentFlowType.java
│       │   │                   │   ├── AgentFlowUsage.java
│       │   │                   │   ├── chat/
│       │   │                   │   │   ├── AgentFlowChatEvent.java
│       │   │                   │   │   ├── AgentFlowChatListener.java
│       │   │                   │   │   ├── AgentFlowChatRequest.java
│       │   │                   │   │   ├── AgentFlowChatResponse.java
│       │   │                   │   │   ├── AgentFlowChatService.java
│       │   │                   │   │   ├── CozeAgentFlowChatService.java
│       │   │                   │   │   └── DifyAgentFlowChatService.java
│       │   │                   │   ├── support/
│       │   │                   │   │   └── AgentFlowSupport.java
│       │   │                   │   ├── trace/
│       │   │                   │   │   ├── AgentFlowTraceContext.java
│       │   │                   │   │   └── AgentFlowTraceListener.java
│       │   │                   │   └── workflow/
│       │   │                   │       ├── AgentFlowWorkflowEvent.java
│       │   │                   │       ├── AgentFlowWorkflowListener.java
│       │   │                   │       ├── AgentFlowWorkflowRequest.java
│       │   │                   │       ├── AgentFlowWorkflowResponse.java
│       │   │                   │       ├── AgentFlowWorkflowService.java
│       │   │                   │       ├── CozeAgentFlowWorkflowService.java
│       │   │                   │       ├── DifyAgentFlowWorkflowService.java
│       │   │                   │       └── N8nAgentFlowWorkflowService.java
│       │   │                   ├── annotation/
│       │   │                   │   ├── FunctionCall.java
│       │   │                   │   ├── FunctionParameter.java
│       │   │                   │   └── FunctionRequest.java
│       │   │                   ├── auth/
│       │   │                   │   └── BearerTokenUtils.java
│       │   │                   ├── config/
│       │   │                   │   ├── AiPlatform.java
│       │   │                   │   ├── BaichuanConfig.java
│       │   │                   │   ├── DashScopeConfig.java
│       │   │                   │   ├── DeepSeekConfig.java
│       │   │                   │   ├── DoubaoConfig.java
│       │   │                   │   ├── HunyuanConfig.java
│       │   │                   │   ├── JinaConfig.java
│       │   │                   │   ├── LingyiConfig.java
│       │   │                   │   ├── McpConfig.java
│       │   │                   │   ├── MilvusConfig.java
│       │   │                   │   ├── MinimaxConfig.java
│       │   │                   │   ├── MoonshotConfig.java
│       │   │                   │   ├── OkHttpConfig.java
│       │   │                   │   ├── OllamaConfig.java
│       │   │                   │   ├── OpenAiConfig.java
│       │   │                   │   ├── PgVectorConfig.java
│       │   │                   │   ├── PineconeConfig.java
│       │   │                   │   ├── QdrantConfig.java
│       │   │                   │   └── ZhipuConfig.java
│       │   │                   ├── constant/
│       │   │                   │   └── Constants.java
│       │   │                   ├── convert/
│       │   │                   │   ├── audio/
│       │   │                   │   │   ├── AudioParameterConvert.java
│       │   │                   │   │   └── AudioResultConvert.java
│       │   │                   │   ├── chat/
│       │   │                   │   │   ├── ParameterConvert.java
│       │   │                   │   │   └── ResultConvert.java
│       │   │                   │   └── embedding/
│       │   │                   │       ├── EmbeddingParameterConvert.java
│       │   │                   │       └── EmbeddingResultConvert.java
│       │   │                   ├── document/
│       │   │                   │   ├── RecursiveCharacterTextSplitter.java
│       │   │                   │   └── TikaUtil.java
│       │   │                   ├── exception/
│       │   │                   │   ├── Ai4jException.java
│       │   │                   │   ├── CommonException.java
│       │   │                   │   ├── chain/
│       │   │                   │   │   ├── AbstractErrorHandler.java
│       │   │                   │   │   ├── ErrorHandler.java
│       │   │                   │   │   ├── IErrorHandler.java
│       │   │                   │   │   └── impl/
│       │   │                   │   │       ├── HunyuanErrorHandler.java
│       │   │                   │   │       ├── OpenAiErrorHandler.java
│       │   │                   │   │       └── UnknownErrorHandler.java
│       │   │                   │   └── error/
│       │   │                   │       ├── Error.java
│       │   │                   │       ├── HunyuanError.java
│       │   │                   │       └── OpenAiError.java
│       │   │                   ├── interceptor/
│       │   │                   │   ├── ContentTypeInterceptor.java
│       │   │                   │   └── ErrorInterceptor.java
│       │   │                   ├── listener/
│       │   │                   │   ├── AbstractManagedStreamListener.java
│       │   │                   │   ├── ImageSseListener.java
│       │   │                   │   ├── ManagedStreamListener.java
│       │   │                   │   ├── RealtimeListener.java
│       │   │                   │   ├── ResponseSseListener.java
│       │   │                   │   ├── SseListener.java
│       │   │                   │   ├── StreamExecutionOptions.java
│       │   │                   │   └── StreamExecutionSupport.java
│       │   │                   ├── mcp/
│       │   │                   │   ├── annotation/
│       │   │                   │   │   ├── McpParameter.java
│       │   │                   │   │   ├── McpPrompt.java
│       │   │                   │   │   ├── McpPromptParameter.java
│       │   │                   │   │   ├── McpResource.java
│       │   │                   │   │   ├── McpResourceParameter.java
│       │   │                   │   │   ├── McpService.java
│       │   │                   │   │   └── McpTool.java
│       │   │                   │   ├── client/
│       │   │                   │   │   ├── McpClient.java
│       │   │                   │   │   └── McpClientResponseSupport.java
│       │   │                   │   ├── config/
│       │   │                   │   │   ├── FileMcpConfigSource.java
│       │   │                   │   │   ├── McpConfigIO.java
│       │   │                   │   │   ├── McpConfigManager.java
│       │   │                   │   │   ├── McpConfigSource.java
│       │   │                   │   │   └── McpServerConfig.java
│       │   │                   │   ├── entity/
│       │   │                   │   │   ├── McpError.java
│       │   │                   │   │   ├── McpInitializeResponse.java
│       │   │                   │   │   ├── McpMessage.java
│       │   │                   │   │   ├── McpNotification.java
│       │   │                   │   │   ├── McpPrompt.java
│       │   │                   │   │   ├── McpPromptResult.java
│       │   │                   │   │   ├── McpRequest.java
│       │   │                   │   │   ├── McpResource.java
│       │   │                   │   │   ├── McpResourceContent.java
│       │   │                   │   │   ├── McpResponse.java
│       │   │                   │   │   ├── McpRoot.java
│       │   │                   │   │   ├── McpSamplingRequest.java
│       │   │                   │   │   ├── McpSamplingResult.java
│       │   │                   │   │   ├── McpServerInfo.java
│       │   │                   │   │   ├── McpServerReference.java
│       │   │                   │   │   ├── McpTool.java
│       │   │                   │   │   ├── McpToolDefinition.java
│       │   │                   │   │   └── McpToolResult.java
│       │   │                   │   ├── gateway/
│       │   │                   │   │   ├── McpGateway.java
│       │   │                   │   │   ├── McpGatewayClientFactory.java
│       │   │                   │   │   ├── McpGatewayConfigSourceBinding.java
│       │   │                   │   │   ├── McpGatewayKeySupport.java
│       │   │                   │   │   └── McpGatewayToolRegistry.java
│       │   │                   │   ├── server/
│       │   │                   │   │   ├── McpHttpServerSupport.java
│       │   │                   │   │   ├── McpServer.java
│       │   │                   │   │   ├── McpServerEngine.java
│       │   │                   │   │   ├── McpServerFactory.java
│       │   │                   │   │   ├── McpServerSessionState.java
│       │   │                   │   │   ├── McpServerSessionSupport.java
│       │   │                   │   │   ├── SseMcpServer.java
│       │   │                   │   │   ├── StdioMcpServer.java
│       │   │                   │   │   └── StreamableHttpMcpServer.java
│       │   │                   │   ├── transport/
│       │   │                   │   │   ├── McpTransport.java
│       │   │                   │   │   ├── McpTransportFactory.java
│       │   │                   │   │   ├── McpTransportSupport.java
│       │   │                   │   │   ├── SseTransport.java
│       │   │                   │   │   ├── StdioTransport.java
│       │   │                   │   │   ├── StreamableHttpTransport.java
│       │   │                   │   │   └── TransportConfig.java
│       │   │                   │   └── util/
│       │   │                   │       ├── McpMessageCodec.java
│       │   │                   │       ├── McpPromptAdapter.java
│       │   │                   │       ├── McpResourceAdapter.java
│       │   │                   │       ├── McpToolAdapter.java
│       │   │                   │       ├── McpToolConversionSupport.java
│       │   │                   │       └── McpTypeSupport.java
│       │   │                   ├── memory/
│       │   │                   │   ├── ChatMemory.java
│       │   │                   │   ├── ChatMemoryItem.java
│       │   │                   │   ├── ChatMemoryPolicy.java
│       │   │                   │   ├── ChatMemorySnapshot.java
│       │   │                   │   ├── ChatMemorySummarizer.java
│       │   │                   │   ├── ChatMemorySummaryRequest.java
│       │   │                   │   ├── InMemoryChatMemory.java
│       │   │                   │   ├── JdbcChatMemory.java
│       │   │                   │   ├── JdbcChatMemoryConfig.java
│       │   │                   │   ├── MessageWindowChatMemoryPolicy.java
│       │   │                   │   ├── SummaryChatMemoryPolicy.java
│       │   │                   │   ├── SummaryChatMemoryPolicyConfig.java
│       │   │                   │   └── UnboundedChatMemoryPolicy.java
│       │   │                   ├── network/
│       │   │                   │   ├── ConnectionPoolProvider.java
│       │   │                   │   ├── DispatcherProvider.java
│       │   │                   │   ├── OkHttpUtil.java
│       │   │                   │   ├── UrlUtils.java
│       │   │                   │   └── impl/
│       │   │                   │       ├── DefaultConnectionPoolProvider.java
│       │   │                   │       └── DefaultDispatcherProvider.java
│       │   │                   ├── platform/
│       │   │                   │   ├── baichuan/
│       │   │                   │   │   └── chat/
│       │   │                   │   │       ├── BaichuanChatService.java
│       │   │                   │   │       └── entity/
│       │   │                   │   │           ├── BaichuanChatCompletion.java
│       │   │                   │   │           └── BaichuanChatCompletionResponse.java
│       │   │                   │   ├── dashscope/
│       │   │                   │   │   ├── DashScopeChatService.java
│       │   │                   │   │   ├── entity/
│       │   │                   │   │   │   └── DashScopeResult.java
│       │   │                   │   │   ├── response/
│       │   │                   │   │   │   └── DashScopeResponsesService.java
│       │   │                   │   │   └── util/
│       │   │                   │   │       └── MessageUtil.java
│       │   │                   │   ├── deepseek/
│       │   │                   │   │   └── chat/
│       │   │                   │   │       ├── DeepSeekChatService.java
│       │   │                   │   │       └── entity/
│       │   │                   │   │           ├── DeepSeekChatCompletion.java
│       │   │                   │   │           └── DeepSeekChatCompletionResponse.java
│       │   │                   │   ├── doubao/
│       │   │                   │   │   ├── chat/
│       │   │                   │   │   │   ├── DoubaoChatService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── DoubaoChatCompletion.java
│       │   │                   │   │   │       └── DoubaoChatCompletionResponse.java
│       │   │                   │   │   ├── image/
│       │   │                   │   │   │   ├── DoubaoImageService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       └── DoubaoImageGenerationRequest.java
│       │   │                   │   │   ├── rerank/
│       │   │                   │   │   │   └── DoubaoRerankService.java
│       │   │                   │   │   └── response/
│       │   │                   │   │       └── DoubaoResponsesService.java
│       │   │                   │   ├── hunyuan/
│       │   │                   │   │   ├── HunyuanConstant.java
│       │   │                   │   │   ├── chat/
│       │   │                   │   │   │   ├── HunyuanChatService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── HunyuanChatCompletion.java
│       │   │                   │   │   │       └── HunyuanChatCompletionResponse.java
│       │   │                   │   │   └── support/
│       │   │                   │   │       └── HunyuanJsonUtil.java
│       │   │                   │   ├── jina/
│       │   │                   │   │   └── rerank/
│       │   │                   │   │       └── JinaRerankService.java
│       │   │                   │   ├── lingyi/
│       │   │                   │   │   └── chat/
│       │   │                   │   │       ├── LingyiChatService.java
│       │   │                   │   │       └── entity/
│       │   │                   │   │           ├── LingyiChatCompletion.java
│       │   │                   │   │           └── LingyiChatCompletionResponse.java
│       │   │                   │   ├── minimax/
│       │   │                   │   │   └── chat/
│       │   │                   │   │       ├── MinimaxChatService.java
│       │   │                   │   │       └── entity/
│       │   │                   │   │           ├── MinimaxChatCompletion.java
│       │   │                   │   │           └── MinimaxChatCompletionResponse.java
│       │   │                   │   ├── moonshot/
│       │   │                   │   │   └── chat/
│       │   │                   │   │       ├── MoonshotChatService.java
│       │   │                   │   │       └── entity/
│       │   │                   │   │           ├── MoonshotChatCompletion.java
│       │   │                   │   │           └── MoonshotChatCompletionResponse.java
│       │   │                   │   ├── ollama/
│       │   │                   │   │   ├── chat/
│       │   │                   │   │   │   ├── OllamaAiChatService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── OllamaChatCompletion.java
│       │   │                   │   │   │       ├── OllamaChatCompletionResponse.java
│       │   │                   │   │   │       ├── OllamaMessage.java
│       │   │                   │   │   │       └── OllamaOptions.java
│       │   │                   │   │   ├── embedding/
│       │   │                   │   │   │   ├── OllamaEmbeddingService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── OllamaEmbedding.java
│       │   │                   │   │   │       └── OllamaEmbeddingResponse.java
│       │   │                   │   │   └── rerank/
│       │   │                   │   │       └── OllamaRerankService.java
│       │   │                   │   ├── openai/
│       │   │                   │   │   ├── audio/
│       │   │                   │   │   │   ├── OpenAiAudioService.java
│       │   │                   │   │   │   ├── entity/
│       │   │                   │   │   │   │   ├── Segment.java
│       │   │                   │   │   │   │   ├── TextToSpeech.java
│       │   │                   │   │   │   │   ├── Transcription.java
│       │   │                   │   │   │   │   ├── TranscriptionResponse.java
│       │   │                   │   │   │   │   ├── Translation.java
│       │   │                   │   │   │   │   ├── TranslationResponse.java
│       │   │                   │   │   │   │   └── Word.java
│       │   │                   │   │   │   └── enums/
│       │   │                   │   │   │       ├── AudioEnum.java
│       │   │                   │   │   │       └── WhisperEnum.java
│       │   │                   │   │   ├── chat/
│       │   │                   │   │   │   ├── OpenAiChatService.java
│       │   │                   │   │   │   ├── entity/
│       │   │                   │   │   │   │   ├── ChatCompletion.java
│       │   │                   │   │   │   │   ├── ChatCompletionResponse.java
│       │   │                   │   │   │   │   ├── ChatMessage.java
│       │   │                   │   │   │   │   ├── Choice.java
│       │   │                   │   │   │   │   ├── Content.java
│       │   │                   │   │   │   │   └── StreamOptions.java
│       │   │                   │   │   │   ├── enums/
│       │   │                   │   │   │   │   └── ChatMessageType.java
│       │   │                   │   │   │   └── serializer/
│       │   │                   │   │   │       └── ContentDeserializer.java
│       │   │                   │   │   ├── embedding/
│       │   │                   │   │   │   ├── OpenAiEmbeddingService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── Embedding.java
│       │   │                   │   │   │       ├── EmbeddingObject.java
│       │   │                   │   │   │       └── EmbeddingResponse.java
│       │   │                   │   │   ├── image/
│       │   │                   │   │   │   ├── OpenAiImageService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── ImageData.java
│       │   │                   │   │   │       ├── ImageGeneration.java
│       │   │                   │   │   │       ├── ImageGenerationResponse.java
│       │   │                   │   │   │       ├── ImageStreamError.java
│       │   │                   │   │   │       ├── ImageStreamEvent.java
│       │   │                   │   │   │       ├── ImageUsage.java
│       │   │                   │   │   │       └── ImageUsageDetails.java
│       │   │                   │   │   ├── realtime/
│       │   │                   │   │   │   ├── OpenAiRealtimeService.java
│       │   │                   │   │   │   ├── RealtimeConstant.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── ConversationCreated.java
│       │   │                   │   │   │       ├── Session.java
│       │   │                   │   │   │       ├── SessionCreated.java
│       │   │                   │   │   │       └── SessionUpdated.java
│       │   │                   │   │   ├── response/
│       │   │                   │   │   │   ├── OpenAiResponsesService.java
│       │   │                   │   │   │   ├── ResponseEventParser.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── ImagePixelLimit.java
│       │   │                   │   │   │       ├── Response.java
│       │   │                   │   │   │       ├── ResponseContentPart.java
│       │   │                   │   │   │       ├── ResponseContextEdit.java
│       │   │                   │   │   │       ├── ResponseContextManagement.java
│       │   │                   │   │   │       ├── ResponseDeleteResponse.java
│       │   │                   │   │   │       ├── ResponseError.java
│       │   │                   │   │   │       ├── ResponseIncompleteDetails.java
│       │   │                   │   │   │       ├── ResponseItem.java
│       │   │                   │   │   │       ├── ResponseRequest.java
│       │   │                   │   │   │       ├── ResponseStreamEvent.java
│       │   │                   │   │   │       ├── ResponseSummary.java
│       │   │                   │   │   │       ├── ResponseToolUsage.java
│       │   │                   │   │   │       ├── ResponseToolUsageDetails.java
│       │   │                   │   │   │       ├── ResponseUsage.java
│       │   │                   │   │   │       ├── ResponseUsageDetails.java
│       │   │                   │   │   │       └── TranslationOptions.java
│       │   │                   │   │   ├── tool/
│       │   │                   │   │   │   ├── Tool.java
│       │   │                   │   │   │   └── ToolCall.java
│       │   │                   │   │   └── usage/
│       │   │                   │   │       └── Usage.java
│       │   │                   │   ├── standard/
│       │   │                   │   │   └── rerank/
│       │   │                   │   │       └── StandardRerankService.java
│       │   │                   │   └── zhipu/
│       │   │                   │       └── chat/
│       │   │                   │           ├── ZhipuChatService.java
│       │   │                   │           └── entity/
│       │   │                   │               ├── ZhipuChatCompletion.java
│       │   │                   │               └── ZhipuChatCompletionResponse.java
│       │   │                   ├── rag/
│       │   │                   │   ├── AbstractScoreFusionStrategy.java
│       │   │                   │   ├── Bm25Retriever.java
│       │   │                   │   ├── DbsfFusionStrategy.java
│       │   │                   │   ├── DefaultRagContextAssembler.java
│       │   │                   │   ├── DefaultRagService.java
│       │   │                   │   ├── DefaultTextTokenizer.java
│       │   │                   │   ├── DenseRetriever.java
│       │   │                   │   ├── FusionStrategy.java
│       │   │                   │   ├── HybridRetriever.java
│       │   │                   │   ├── ModelReranker.java
│       │   │                   │   ├── NoopReranker.java
│       │   │                   │   ├── RagChunk.java
│       │   │                   │   ├── RagCitation.java
│       │   │                   │   ├── RagContext.java
│       │   │                   │   ├── RagContextAssembler.java
│       │   │                   │   ├── RagDocument.java
│       │   │                   │   ├── RagEvaluation.java
│       │   │                   │   ├── RagEvaluator.java
│       │   │                   │   ├── RagHit.java
│       │   │                   │   ├── RagHitSupport.java
│       │   │                   │   ├── RagMetadataKeys.java
│       │   │                   │   ├── RagQuery.java
│       │   │                   │   ├── RagResult.java
│       │   │                   │   ├── RagScoreDetail.java
│       │   │                   │   ├── RagService.java
│       │   │                   │   ├── RagTrace.java
│       │   │                   │   ├── Reranker.java
│       │   │                   │   ├── Retriever.java
│       │   │                   │   ├── RrfFusionStrategy.java
│       │   │                   │   ├── RsfFusionStrategy.java
│       │   │                   │   ├── TextTokenizer.java
│       │   │                   │   └── ingestion/
│       │   │                   │       ├── Chunker.java
│       │   │                   │       ├── DefaultMetadataEnricher.java
│       │   │                   │       ├── DocumentLoader.java
│       │   │                   │       ├── IngestionPipeline.java
│       │   │                   │       ├── IngestionRequest.java
│       │   │                   │       ├── IngestionResult.java
│       │   │                   │       ├── IngestionSource.java
│       │   │                   │       ├── LoadedDocument.java
│       │   │                   │       ├── LoadedDocumentProcessor.java
│       │   │                   │       ├── MetadataEnricher.java
│       │   │                   │       ├── OcrNoiseCleaningDocumentProcessor.java
│       │   │                   │       ├── OcrTextExtractingDocumentProcessor.java
│       │   │                   │       ├── OcrTextExtractor.java
│       │   │                   │       ├── RecursiveTextChunker.java
│       │   │                   │       ├── TextDocumentLoader.java
│       │   │                   │       ├── TikaDocumentLoader.java
│       │   │                   │       └── WhitespaceNormalizingDocumentProcessor.java
│       │   │                   ├── rerank/
│       │   │                   │   └── entity/
│       │   │                   │       ├── RerankDocument.java
│       │   │                   │       ├── RerankRequest.java
│       │   │                   │       ├── RerankResponse.java
│       │   │                   │       ├── RerankResult.java
│       │   │                   │       └── RerankUsage.java
│       │   │                   ├── service/
│       │   │                   │   ├── AiConfig.java
│       │   │                   │   ├── Configuration.java
│       │   │                   │   ├── IAudioService.java
│       │   │                   │   ├── IChatService.java
│       │   │                   │   ├── IEmbeddingService.java
│       │   │                   │   ├── IImageService.java
│       │   │                   │   ├── IRealtimeService.java
│       │   │                   │   ├── IRerankService.java
│       │   │                   │   ├── IResponsesService.java
│       │   │                   │   ├── ModelType.java
│       │   │                   │   ├── PlatformType.java
│       │   │                   │   ├── factory/
│       │   │                   │   │   ├── AiService.java
│       │   │                   │   │   ├── AiServiceFactory.java
│       │   │                   │   │   ├── AiServiceRegistration.java
│       │   │                   │   │   ├── AiServiceRegistry.java
│       │   │                   │   │   ├── DefaultAiServiceFactory.java
│       │   │                   │   │   ├── DefaultAiServiceRegistry.java
│       │   │                   │   │   └── FreeAiService.java
│       │   │                   │   └── spi/
│       │   │                   │       └── ServiceLoaderUtil.java
│       │   │                   ├── skill/
│       │   │                   │   ├── SkillDescriptor.java
│       │   │                   │   └── Skills.java
│       │   │                   ├── token/
│       │   │                   │   └── TikTokensUtil.java
│       │   │                   ├── tool/
│       │   │                   │   ├── BuiltInProcessRegistry.java
│       │   │                   │   ├── BuiltInToolContext.java
│       │   │                   │   ├── BuiltInToolExecutor.java
│       │   │                   │   ├── BuiltInTools.java
│       │   │                   │   ├── ResponseRequestToolResolver.java
│       │   │                   │   └── ToolUtil.java
│       │   │                   ├── tools/
│       │   │                   │   ├── ApplyPatchFunction.java
│       │   │                   │   ├── BashFunction.java
│       │   │                   │   ├── QueryTrainInfoFunction.java
│       │   │                   │   ├── QueryWeatherFunction.java
│       │   │                   │   ├── ReadFileFunction.java
│       │   │                   │   └── WriteFileFunction.java
│       │   │                   ├── vector/
│       │   │                   │   ├── VectorDataEntity.java
│       │   │                   │   ├── pinecone/
│       │   │                   │   │   ├── PineconeDelete.java
│       │   │                   │   │   ├── PineconeInsert.java
│       │   │                   │   │   ├── PineconeInsertResponse.java
│       │   │                   │   │   ├── PineconeQuery.java
│       │   │                   │   │   ├── PineconeQueryResponse.java
│       │   │                   │   │   └── PineconeVectors.java
│       │   │                   │   ├── service/
│       │   │                   │   │   └── PineconeService.java
│       │   │                   │   └── store/
│       │   │                   │       ├── VectorDeleteRequest.java
│       │   │                   │       ├── VectorRecord.java
│       │   │                   │       ├── VectorSearchRequest.java
│       │   │                   │       ├── VectorSearchResult.java
│       │   │                   │       ├── VectorStore.java
│       │   │                   │       ├── VectorStoreCapabilities.java
│       │   │                   │       ├── VectorUpsertRequest.java
│       │   │                   │       ├── milvus/
│       │   │                   │       │   └── MilvusVectorStore.java
│       │   │                   │       ├── pgvector/
│       │   │                   │       │   └── PgVectorStore.java
│       │   │                   │       ├── pinecone/
│       │   │                   │       │   └── PineconeVectorStore.java
│       │   │                   │       └── qdrant/
│       │   │                   │           └── QdrantVectorStore.java
│       │   │                   └── websearch/
│       │   │                       ├── ChatWithWebSearchEnhance.java
│       │   │                       └── searxng/
│       │   │                           ├── SearXNGConfig.java
│       │   │                           ├── SearXNGRequest.java
│       │   │                           └── SearXNGResponse.java
│       │   └── resources/
│       │       ├── META-INF/
│       │       │   └── services/
│       │       │       ├── io.github.lnyocly.ai4j.network.ConnectionPoolProvider
│       │       │       └── io.github.lnyocly.ai4j.network.DispatcherProvider
│       │       └── mcp-servers-config.json
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           ├── BaichuanTest.java
│                           ├── DashScopeTest.java
│                           ├── DeepSeekTest.java
│                           ├── DoubaoImageTest.java
│                           ├── DoubaoResponsesTest.java
│                           ├── DoubaoTest.java
│                           ├── HunyuanTest.java
│                           ├── LingyiTest.java
│                           ├── MinimaxTest.java
│                           ├── MoonshotTest.java
│                           ├── OllamaTest.java
│                           ├── OpenAiTest.java
│                           ├── OtherTest.java
│                           ├── ZhipuTest.java
│                           ├── ai4j/
│                           │   ├── agentflow/
│                           │   │   ├── AgentFlowTraceSupportTest.java
│                           │   │   ├── CozeAgentFlowServiceTest.java
│                           │   │   ├── DifyAgentFlowServiceTest.java
│                           │   │   └── N8nAgentFlowWorkflowServiceTest.java
│                           │   ├── function/
│                           │   │   └── TestFunction.java
│                           │   ├── mcp/
│                           │   │   ├── McpClientResponseSupportTest.java
│                           │   │   ├── McpGatewaySupportTest.java
│                           │   │   ├── McpServerTest.java
│                           │   │   ├── McpTypeSupportTest.java
│                           │   │   ├── TestMcpService.java
│                           │   │   ├── config/
│                           │   │   │   └── McpConfigManagerTest.java
│                           │   │   ├── gateway/
│                           │   │   │   └── McpGatewayConfigSourceTest.java
│                           │   │   ├── transport/
│                           │   │   │   └── SseTransportTest.java
│                           │   │   └── util/
│                           │   │       └── TestMcpService.java
│                           │   ├── memory/
│                           │   │   ├── InMemoryChatMemoryTest.java
│                           │   │   ├── JdbcChatMemoryTest.java
│                           │   │   └── SummaryChatMemoryPolicyTest.java
│                           │   ├── platform/
│                           │   │   ├── doubao/
│                           │   │   │   └── rerank/
│                           │   │   │       └── DoubaoRerankServiceTest.java
│                           │   │   ├── jina/
│                           │   │   │   └── rerank/
│                           │   │   │       └── JinaRerankServiceTest.java
│                           │   │   ├── minimax/
│                           │   │   │   └── chat/
│                           │   │   │       └── MinimaxChatServiceTest.java
│                           │   │   ├── ollama/
│                           │   │   │   └── rerank/
│                           │   │   │       └── OllamaRerankServiceTest.java
│                           │   │   └── openai/
│                           │   │       ├── audio/
│                           │   │       │   └── OpenAiAudioServiceTest.java
│                           │   │       ├── chat/
│                           │   │       │   └── OpenAiChatServicePassThroughTest.java
│                           │   │       └── response/
│                           │   │           └── ResponseRequestToolResolverTest.java
│                           │   ├── rag/
│                           │   │   ├── Bm25RetrieverTest.java
│                           │   │   ├── DefaultRagServiceTest.java
│                           │   │   ├── DenseRetrieverTest.java
│                           │   │   ├── HybridRetrieverTest.java
│                           │   │   ├── IngestionPipelineTest.java
│                           │   │   ├── ModelRerankerTest.java
│                           │   │   └── RagEvaluatorTest.java
│                           │   ├── skill/
│                           │   │   └── SkillsIChatServiceTest.java
│                           │   ├── tool/
│                           │   │   └── BuiltInToolExecutorTest.java
│                           │   └── vector/
│                           │       └── store/
│                           │           ├── milvus/
│                           │           │   └── MilvusVectorStoreTest.java
│                           │           ├── pinecone/
│                           │           │   └── PineconeVectorStoreTest.java
│                           │           └── qdrant/
│                           │               └── QdrantVectorStoreTest.java
│                           ├── interceptor/
│                           │   └── ErrorInterceptorTest.java
│                           ├── listener/
│                           │   ├── SseListenerTest.java
│                           │   └── StreamExecutionSupportTest.java
│                           └── service/
│                               └── AiServiceRegistryTest.java
├── ai4j-agent/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── io/
│       │           └── github/
│       │               └── lnyocly/
│       │                   └── ai4j/
│       │                       └── agent/
│       │                           ├── Agent.java
│       │                           ├── AgentBuilder.java
│       │                           ├── AgentContext.java
│       │                           ├── AgentOptions.java
│       │                           ├── AgentRequest.java
│       │                           ├── AgentResult.java
│       │                           ├── AgentRuntime.java
│       │                           ├── AgentSession.java
│       │                           ├── Agents.java
│       │                           ├── codeact/
│       │                           │   ├── CodeActOptions.java
│       │                           │   ├── CodeExecutionRequest.java
│       │                           │   ├── CodeExecutionResult.java
│       │                           │   ├── CodeExecutor.java
│       │                           │   ├── GraalVmCodeExecutor.java
│       │                           │   └── NashornCodeExecutor.java
│       │                           ├── event/
│       │                           │   ├── AgentEvent.java
│       │                           │   ├── AgentEventPublisher.java
│       │                           │   ├── AgentEventType.java
│       │                           │   └── AgentListener.java
│       │                           ├── flowgram/
│       │                           │   ├── Ai4jFlowGramLlmNodeRunner.java
│       │                           │   ├── FlowGramLlmNodeRunner.java
│       │                           │   ├── FlowGramNodeExecutionContext.java
│       │                           │   ├── FlowGramNodeExecutionResult.java
│       │                           │   ├── FlowGramNodeExecutor.java
│       │                           │   ├── FlowGramRuntimeEvent.java
│       │                           │   ├── FlowGramRuntimeListener.java
│       │                           │   ├── FlowGramRuntimeService.java
│       │                           │   └── model/
│       │                           │       ├── FlowGramEdgeSchema.java
│       │                           │       ├── FlowGramNodeSchema.java
│       │                           │       ├── FlowGramTaskCancelOutput.java
│       │                           │       ├── FlowGramTaskReportOutput.java
│       │                           │       ├── FlowGramTaskResultOutput.java
│       │                           │       ├── FlowGramTaskRunInput.java
│       │                           │       ├── FlowGramTaskRunOutput.java
│       │                           │       ├── FlowGramTaskValidateOutput.java
│       │                           │       └── FlowGramWorkflowSchema.java
│       │                           ├── memory/
│       │                           │   ├── AgentMemory.java
│       │                           │   ├── InMemoryAgentMemory.java
│       │                           │   ├── JdbcAgentMemory.java
│       │                           │   ├── JdbcAgentMemoryConfig.java
│       │                           │   ├── MemoryCompressor.java
│       │                           │   ├── MemorySnapshot.java
│       │                           │   └── WindowedMemoryCompressor.java
│       │                           ├── model/
│       │                           │   ├── AgentModelClient.java
│       │                           │   ├── AgentModelResult.java
│       │                           │   ├── AgentModelStreamListener.java
│       │                           │   ├── AgentPrompt.java
│       │                           │   ├── ChatModelClient.java
│       │                           │   └── ResponsesModelClient.java
│       │                           ├── runtime/
│       │                           │   ├── AgentToolExecutionScope.java
│       │                           │   ├── BaseAgentRuntime.java
│       │                           │   ├── CodeActRuntime.java
│       │                           │   ├── DeepResearchRuntime.java
│       │                           │   ├── Planner.java
│       │                           │   └── ReActRuntime.java
│       │                           ├── subagent/
│       │                           │   ├── HandoffContext.java
│       │                           │   ├── HandoffFailureAction.java
│       │                           │   ├── HandoffInputFilter.java
│       │                           │   ├── HandoffPolicy.java
│       │                           │   ├── StaticSubAgentRegistry.java
│       │                           │   ├── SubAgentDefinition.java
│       │                           │   ├── SubAgentRegistry.java
│       │                           │   ├── SubAgentSessionMode.java
│       │                           │   └── SubAgentToolExecutor.java
│       │                           ├── team/
│       │                           │   ├── AgentTeam.java
│       │                           │   ├── AgentTeamAgentRuntime.java
│       │                           │   ├── AgentTeamBuilder.java
│       │                           │   ├── AgentTeamControl.java
│       │                           │   ├── AgentTeamEventHook.java
│       │                           │   ├── AgentTeamHook.java
│       │                           │   ├── AgentTeamMember.java
│       │                           │   ├── AgentTeamMemberResult.java
│       │                           │   ├── AgentTeamMemberSnapshot.java
│       │                           │   ├── AgentTeamMessage.java
│       │                           │   ├── AgentTeamMessageBus.java
│       │                           │   ├── AgentTeamOptions.java
│       │                           │   ├── AgentTeamPlan.java
│       │                           │   ├── AgentTeamPlanApproval.java
│       │                           │   ├── AgentTeamPlanParser.java
│       │                           │   ├── AgentTeamPlanner.java
│       │                           │   ├── AgentTeamResult.java
│       │                           │   ├── AgentTeamState.java
│       │                           │   ├── AgentTeamStateStore.java
│       │                           │   ├── AgentTeamSynthesizer.java
│       │                           │   ├── AgentTeamTask.java
│       │                           │   ├── AgentTeamTaskBoard.java
│       │                           │   ├── AgentTeamTaskState.java
│       │                           │   ├── AgentTeamTaskStatus.java
│       │                           │   ├── FileAgentTeamMessageBus.java
│       │                           │   ├── FileAgentTeamStateStore.java
│       │                           │   ├── InMemoryAgentTeamMessageBus.java
│       │                           │   ├── InMemoryAgentTeamStateStore.java
│       │                           │   ├── LlmAgentTeamPlanner.java
│       │                           │   ├── LlmAgentTeamSynthesizer.java
│       │                           │   └── tool/
│       │                           │       ├── AgentTeamToolExecutor.java
│       │                           │       └── AgentTeamToolRegistry.java
│       │                           ├── tool/
│       │                           │   ├── AgentToolCall.java
│       │                           │   ├── AgentToolCallSanitizer.java
│       │                           │   ├── AgentToolRegistry.java
│       │                           │   ├── AgentToolResult.java
│       │                           │   ├── CompositeToolRegistry.java
│       │                           │   ├── StaticToolRegistry.java
│       │                           │   ├── ToolExecutor.java
│       │                           │   ├── ToolUtilExecutor.java
│       │                           │   └── ToolUtilRegistry.java
│       │                           ├── trace/
│       │                           │   ├── AbstractOpenTelemetryTraceExporter.java
│       │                           │   ├── AgentFlowTraceBridge.java
│       │                           │   ├── AgentTraceListener.java
│       │                           │   ├── CompositeTraceExporter.java
│       │                           │   ├── ConsoleTraceExporter.java
│       │                           │   ├── InMemoryTraceExporter.java
│       │                           │   ├── JsonlTraceExporter.java
│       │                           │   ├── LangfuseTraceExporter.java
│       │                           │   ├── OpenTelemetryTraceExporter.java
│       │                           │   ├── OpenTelemetryTraceSupport.java
│       │                           │   ├── TraceConfig.java
│       │                           │   ├── TraceExporter.java
│       │                           │   ├── TraceMasker.java
│       │                           │   ├── TraceMetrics.java
│       │                           │   ├── TracePricing.java
│       │                           │   ├── TracePricingResolver.java
│       │                           │   ├── TraceSpan.java
│       │                           │   ├── TraceSpanEvent.java
│       │                           │   ├── TraceSpanStatus.java
│       │                           │   └── TraceSpanType.java
│       │                           ├── util/
│       │                           │   ├── AgentInputItem.java
│       │                           │   └── ResponseUtil.java
│       │                           └── workflow/
│       │                               ├── AgentNode.java
│       │                               ├── AgentWorkflow.java
│       │                               ├── RuntimeAgentNode.java
│       │                               ├── SequentialWorkflow.java
│       │                               ├── StateCondition.java
│       │                               ├── StateGraphWorkflow.java
│       │                               ├── StateRouter.java
│       │                               ├── StateTransition.java
│       │                               ├── WorkflowAgent.java
│       │                               ├── WorkflowContext.java
│       │                               └── WorkflowResultAware.java
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           ├── agent/
│                           │   ├── AgentFlowTraceBridgeTest.java
│                           │   ├── AgentMemoryTest.java
│                           │   ├── AgentRuntimeTest.java
│                           │   ├── AgentTeamAgentAdapterTest.java
│                           │   ├── AgentTeamPersistenceTest.java
│                           │   ├── AgentTeamProjectDeliveryExampleTest.java
│                           │   ├── AgentTeamTaskBoardTest.java
│                           │   ├── AgentTeamTest.java
│                           │   ├── AgentTeamUsageTest.java
│                           │   ├── AgentTraceListenerTest.java
│                           │   ├── AgentTraceUsageTest.java
│                           │   ├── AgentWorkflowTest.java
│                           │   ├── AgentWorkflowUsageTest.java
│                           │   ├── ChatModelClientTest.java
│                           │   ├── CodeActAgentUsageTest.java
│                           │   ├── CodeActPythonExecutorTest.java
│                           │   ├── CodeActRuntimeTest.java
│                           │   ├── CodeActRuntimeWithTraceTest.java
│                           │   ├── DoubaoAgentTeamBestPracticeTest.java
│                           │   ├── DoubaoAgentWorkflowTest.java
│                           │   ├── DoubaoProjectTeamAgentTeamsTest.java
│                           │   ├── FileAgentTeamStateStoreTest.java
│                           │   ├── HandoffPolicyTest.java
│                           │   ├── MinimaxAgentTeamTravelUsageTest.java
│                           │   ├── NashornCodeExecutorTest.java
│                           │   ├── ReActAgentUsageTest.java
│                           │   ├── ResponsesModelClientTest.java
│                           │   ├── StateGraphWorkflowTest.java
│                           │   ├── SubAgentParallelFallbackTest.java
│                           │   ├── SubAgentRuntimeTest.java
│                           │   ├── SubAgentUsageTest.java
│                           │   ├── ToolUtilExecutorRestrictionTest.java
│                           │   ├── UniversalAgentUsageTest.java
│                           │   ├── WeatherAgentWorkflowTest.java
│                           │   └── support/
│                           │       └── ZhipuAgentTestSupport.java
│                           └── ai4j/
│                               └── agent/
│                                   ├── flowgram/
│                                   │   └── FlowGramRuntimeServiceTest.java
│                                   ├── memory/
│                                   │   └── JdbcAgentMemoryTest.java
│                                   ├── model/
│                                   │   └── ChatModelClientTest.java
│                                   └── trace/
│                                       └── LangfuseTraceExporterTest.java
├── ai4j-bom/
│   └── pom.xml
├── ai4j-cli/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── github/
│       │   │           └── lnyocly/
│       │   │               └── ai4j/
│       │   │                   ├── cli/
│       │   │                   │   ├── Ai4jCli.java
│       │   │                   │   ├── Ai4jCliMain.java
│       │   │                   │   ├── ApprovalMode.java
│       │   │                   │   ├── CliProtocol.java
│       │   │                   │   ├── CliUiMode.java
│       │   │                   │   ├── SlashCommandController.java
│       │   │                   │   ├── acp/
│       │   │                   │   │   ├── AcpCodingCliAgentFactory.java
│       │   │                   │   │   ├── AcpCommand.java
│       │   │                   │   │   ├── AcpJsonRpcServer.java
│       │   │                   │   │   ├── AcpSlashCommandSupport.java
│       │   │                   │   │   └── AcpToolApprovalDecorator.java
│       │   │                   │   ├── agent/
│       │   │                   │   │   └── CliCodingAgentRegistry.java
│       │   │                   │   ├── command/
│       │   │                   │   │   ├── CodeCommand.java
│       │   │                   │   │   ├── CodeCommandOptions.java
│       │   │                   │   │   ├── CodeCommandOptionsParser.java
│       │   │                   │   │   ├── CustomCommandRegistry.java
│       │   │                   │   │   └── CustomCommandTemplate.java
│       │   │                   │   ├── config/
│       │   │                   │   │   └── CliWorkspaceConfig.java
│       │   │                   │   ├── factory/
│       │   │                   │   │   ├── CodingCliAgentFactory.java
│       │   │                   │   │   ├── CodingCliTuiFactory.java
│       │   │                   │   │   ├── DefaultCodingCliAgentFactory.java
│       │   │                   │   │   └── DefaultCodingCliTuiFactory.java
│       │   │                   │   ├── mcp/
│       │   │                   │   │   ├── CliMcpConfig.java
│       │   │                   │   │   ├── CliMcpConfigManager.java
│       │   │                   │   │   ├── CliMcpConnectionHandle.java
│       │   │                   │   │   ├── CliMcpRuntimeManager.java
│       │   │                   │   │   ├── CliMcpServerDefinition.java
│       │   │                   │   │   ├── CliMcpStatusSnapshot.java
│       │   │                   │   │   ├── CliResolvedMcpConfig.java
│       │   │                   │   │   └── CliResolvedMcpServer.java
│       │   │                   │   ├── provider/
│       │   │                   │   │   ├── CliProviderConfigManager.java
│       │   │                   │   │   ├── CliProviderProfile.java
│       │   │                   │   │   ├── CliProvidersConfig.java
│       │   │                   │   │   └── CliResolvedProviderConfig.java
│       │   │                   │   ├── render/
│       │   │                   │   │   ├── AssistantTranscriptRenderer.java
│       │   │                   │   │   ├── CliAnsi.java
│       │   │                   │   │   ├── CliDisplayWidth.java
│       │   │                   │   │   ├── CliThemeStyler.java
│       │   │                   │   │   ├── CodexStyleBlockFormatter.java
│       │   │                   │   │   ├── PatchSummaryFormatter.java
│       │   │                   │   │   └── TranscriptPrinter.java
│       │   │                   │   ├── runtime/
│       │   │                   │   │   ├── AgentHandoffSessionEventSupport.java
│       │   │                   │   │   ├── AgentTeamMessageSessionEventSupport.java
│       │   │                   │   │   ├── AgentTeamSessionEventSupport.java
│       │   │                   │   │   ├── CliTeamStateManager.java
│       │   │                   │   │   ├── CliToolApprovalDecorator.java
│       │   │                   │   │   ├── CodingCliSessionRunner.java
│       │   │                   │   │   ├── CodingCliTuiSupport.java
│       │   │                   │   │   ├── CodingTaskSessionEventBridge.java
│       │   │                   │   │   ├── HeadlessCodingSessionRuntime.java
│       │   │                   │   │   ├── HeadlessTurnObserver.java
│       │   │                   │   │   └── TeamBoardRenderSupport.java
│       │   │                   │   ├── session/
│       │   │                   │   │   ├── CodingSessionManager.java
│       │   │                   │   │   ├── CodingSessionStore.java
│       │   │                   │   │   ├── DefaultCodingSessionManager.java
│       │   │                   │   │   ├── FileCodingSessionStore.java
│       │   │                   │   │   ├── FileSessionEventStore.java
│       │   │                   │   │   ├── InMemoryCodingSessionStore.java
│       │   │                   │   │   ├── InMemorySessionEventStore.java
│       │   │                   │   │   ├── SessionEventStore.java
│       │   │                   │   │   └── StoredCodingSession.java
│       │   │                   │   └── shell/
│       │   │                   │       ├── JlineCodeCommandRunner.java
│       │   │                   │       ├── JlineShellContext.java
│       │   │                   │       ├── JlineShellTerminalIO.java
│       │   │                   │       └── WindowsConsoleKeyPoller.java
│       │   │                   └── tui/
│       │   │                       ├── AnsiTuiRuntime.java
│       │   │                       ├── AppendOnlyTuiRuntime.java
│       │   │                       ├── JlineTerminalIO.java
│       │   │                       ├── StreamsTerminalIO.java
│       │   │                       ├── TerminalIO.java
│       │   │                       ├── TuiAnsi.java
│       │   │                       ├── TuiAssistantPhase.java
│       │   │                       ├── TuiAssistantToolView.java
│       │   │                       ├── TuiAssistantViewModel.java
│       │   │                       ├── TuiConfig.java
│       │   │                       ├── TuiConfigManager.java
│       │   │                       ├── TuiInteractionState.java
│       │   │                       ├── TuiKeyStroke.java
│       │   │                       ├── TuiKeyType.java
│       │   │                       ├── TuiPaletteItem.java
│       │   │                       ├── TuiPanelId.java
│       │   │                       ├── TuiRenderContext.java
│       │   │                       ├── TuiRenderer.java
│       │   │                       ├── TuiRuntime.java
│       │   │                       ├── TuiScreenModel.java
│       │   │                       ├── TuiSessionView.java
│       │   │                       ├── TuiTheme.java
│       │   │                       ├── io/
│       │   │                       │   ├── DefaultJlineTerminalIO.java
│       │   │                       │   └── DefaultStreamsTerminalIO.java
│       │   │                       └── runtime/
│       │   │                           ├── DefaultAnsiTuiRuntime.java
│       │   │                           └── DefaultAppendOnlyTuiRuntime.java
│       │   └── resources/
│       │       └── io/
│       │           └── github/
│       │               └── lnyocly/
│       │                   └── ai4j/
│       │                       └── tui/
│       │                           └── themes/
│       │                               ├── amber.json
│       │                               ├── default.json
│       │                               ├── github-dark.json
│       │                               ├── github-light.json
│       │                               ├── matrix.json
│       │                               └── ocean.json
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           └── ai4j/
│                               ├── cli/
│                               │   ├── Ai4jCliTest.java
│                               │   ├── AssistantTranscriptRendererTest.java
│                               │   ├── CliDisplayWidthTest.java
│                               │   ├── CliMcpConfigManagerTest.java
│                               │   ├── CliMcpRuntimeManagerTest.java
│                               │   ├── CliProviderConfigManagerTest.java
│                               │   ├── CliThemeStylerTest.java
│                               │   ├── CodeCommandOptionsParserTest.java
│                               │   ├── CodeCommandTest.java
│                               │   ├── CodexStyleBlockFormatterTest.java
│                               │   ├── DefaultCodingCliAgentFactoryTest.java
│                               │   ├── DefaultCodingSessionManagerTest.java
│                               │   ├── FileCodingSessionStoreTest.java
│                               │   ├── FileSessionEventStoreTest.java
│                               │   ├── JlineShellTerminalIOTest.java
│                               │   ├── PatchSummaryFormatterTest.java
│                               │   ├── SlashCommandControllerTest.java
│                               │   ├── TranscriptPrinterTest.java
│                               │   ├── acp/
│                               │   │   ├── AcpCommandTest.java
│                               │   │   └── AcpSlashCommandSupportTest.java
│                               │   ├── agent/
│                               │   │   └── CliCodingAgentRegistryTest.java
│                               │   └── runtime/
│                               │       ├── AgentHandoffSessionEventSupportTest.java
│                               │       ├── AgentTeamMessageSessionEventSupportTest.java
│                               │       ├── AgentTeamSessionEventSupportTest.java
│                               │       ├── CodingTaskSessionEventBridgeTest.java
│                               │       └── HeadlessCodingSessionRuntimeTest.java
│                               └── tui/
│                                   ├── AnsiTuiRuntimeTest.java
│                                   ├── AppendOnlyTuiRuntimeTest.java
│                                   ├── StreamsTerminalIOTest.java
│                                   ├── TuiConfigManagerTest.java
│                                   ├── TuiInteractionStateTest.java
│                                   └── TuiSessionViewTest.java
├── ai4j-coding/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── io/
│       │           └── github/
│       │               └── lnyocly/
│       │                   └── ai4j/
│       │                       └── coding/
│       │                           ├── CodingAgent.java
│       │                           ├── CodingAgentBuilder.java
│       │                           ├── CodingAgentOptions.java
│       │                           ├── CodingAgentRequest.java
│       │                           ├── CodingAgentResult.java
│       │                           ├── CodingAgents.java
│       │                           ├── CodingSession.java
│       │                           ├── CodingSessionCheckpoint.java
│       │                           ├── CodingSessionCheckpointFormatter.java
│       │                           ├── CodingSessionCompactResult.java
│       │                           ├── CodingSessionScope.java
│       │                           ├── CodingSessionSnapshot.java
│       │                           ├── CodingSessionState.java
│       │                           ├── compact/
│       │                           │   ├── CodingCompactionPreparation.java
│       │                           │   ├── CodingSessionCompactor.java
│       │                           │   ├── CodingToolResultMicroCompactResult.java
│       │                           │   └── CodingToolResultMicroCompactor.java
│       │                           ├── definition/
│       │                           │   ├── BuiltInCodingAgentDefinitions.java
│       │                           │   ├── CodingAgentDefinition.java
│       │                           │   ├── CodingAgentDefinitionRegistry.java
│       │                           │   ├── CodingApprovalMode.java
│       │                           │   ├── CodingIsolationMode.java
│       │                           │   ├── CodingMemoryScope.java
│       │                           │   ├── CodingSessionMode.java
│       │                           │   ├── CompositeCodingAgentDefinitionRegistry.java
│       │                           │   └── StaticCodingAgentDefinitionRegistry.java
│       │                           ├── delegate/
│       │                           │   ├── CodingDelegateRequest.java
│       │                           │   ├── CodingDelegateResult.java
│       │                           │   ├── CodingDelegateToolExecutor.java
│       │                           │   └── CodingDelegateToolRegistry.java
│       │                           ├── loop/
│       │                           │   ├── CodingAgentLoopController.java
│       │                           │   ├── CodingContinuationPrompt.java
│       │                           │   ├── CodingLoopDecision.java
│       │                           │   ├── CodingLoopPolicy.java
│       │                           │   └── CodingStopReason.java
│       │                           ├── patch/
│       │                           │   ├── ApplyPatchFileChange.java
│       │                           │   └── ApplyPatchResult.java
│       │                           ├── policy/
│       │                           │   ├── CodingToolContextPolicy.java
│       │                           │   └── CodingToolPolicyResolver.java
│       │                           ├── process/
│       │                           │   ├── BashProcessInfo.java
│       │                           │   ├── BashProcessLogChunk.java
│       │                           │   ├── BashProcessStatus.java
│       │                           │   ├── SessionProcessRegistry.java
│       │                           │   └── StoredProcessSnapshot.java
│       │                           ├── prompt/
│       │                           │   └── CodingContextPromptAssembler.java
│       │                           ├── runtime/
│       │                           │   ├── CodingRuntime.java
│       │                           │   ├── CodingRuntimeListener.java
│       │                           │   └── DefaultCodingRuntime.java
│       │                           ├── session/
│       │                           │   ├── CodingSessionDescriptor.java
│       │                           │   ├── CodingSessionLink.java
│       │                           │   ├── CodingSessionLinkStore.java
│       │                           │   ├── InMemoryCodingSessionLinkStore.java
│       │                           │   ├── ManagedCodingSession.java
│       │                           │   ├── SessionEvent.java
│       │                           │   └── SessionEventType.java
│       │                           ├── shell/
│       │                           │   ├── LocalShellCommandExecutor.java
│       │                           │   ├── ShellCommandExecutor.java
│       │                           │   ├── ShellCommandRequest.java
│       │                           │   ├── ShellCommandResult.java
│       │                           │   └── ShellCommandSupport.java
│       │                           ├── skill/
│       │                           │   ├── CodingSkillDescriptor.java
│       │                           │   └── CodingSkillDiscovery.java
│       │                           ├── task/
│       │                           │   ├── CodingTask.java
│       │                           │   ├── CodingTaskManager.java
│       │                           │   ├── CodingTaskProgress.java
│       │                           │   ├── CodingTaskStatus.java
│       │                           │   └── InMemoryCodingTaskManager.java
│       │                           ├── tool/
│       │                           │   ├── ApplyPatchToolExecutor.java
│       │                           │   ├── BashToolExecutor.java
│       │                           │   ├── CodingToolNames.java
│       │                           │   ├── CodingToolRegistryFactory.java
│       │                           │   ├── ReadFileToolExecutor.java
│       │                           │   ├── RoutingToolExecutor.java
│       │                           │   ├── ToolExecutorDecorator.java
│       │                           │   └── WriteFileToolExecutor.java
│       │                           └── workspace/
│       │                               ├── LocalWorkspaceFileService.java
│       │                               ├── WorkspaceContext.java
│       │                               ├── WorkspaceEntry.java
│       │                               ├── WorkspaceFileReadResult.java
│       │                               ├── WorkspaceFileService.java
│       │                               └── WorkspaceWriteResult.java
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           └── ai4j/
│                               └── coding/
│                                   ├── ApplyPatchToolExecutorTest.java
│                                   ├── BashToolExecutorTest.java
│                                   ├── CodingAgentBuilderTest.java
│                                   ├── CodingRuntimeTest.java
│                                   ├── CodingSessionCheckpointFormatterTest.java
│                                   ├── CodingSessionTest.java
│                                   ├── CodingSkillSupportTest.java
│                                   ├── LocalShellCommandExecutorTest.java
│                                   ├── MinimaxCodingAgentTeamWorkspaceUsageTest.java
│                                   ├── ReadFileToolExecutorTest.java
│                                   ├── WriteFileToolExecutorTest.java
│                                   ├── loop/
│                                   │   └── CodingAgentLoopControllerTest.java
│                                   └── shell/
│                                       └── ShellCommandSupportTest.java
├── ai4j-flowgram-demo/
│   ├── README.md
│   ├── backend-18080-run.log
│   ├── backend-18080.log
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── io/
│           │       └── github/
│           │           └── lnyocly/
│           │               └── ai4j/
│           │                   └── flowgram/
│           │                       └── demo/
│           │                           ├── FlowGramDemoApplication.java
│           │                           └── FlowGramDemoMockController.java
│           └── resources/
│               └── application.yml
├── ai4j-flowgram-spring-boot-starter/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── github/
│       │   │           └── lnyocly/
│       │   │               └── ai4j/
│       │   │                   └── flowgram/
│       │   │                       └── springboot/
│       │   │                           ├── adapter/
│       │   │                           │   └── FlowGramProtocolAdapter.java
│       │   │                           ├── autoconfigure/
│       │   │                           │   └── FlowGramAutoConfiguration.java
│       │   │                           ├── config/
│       │   │                           │   └── FlowGramProperties.java
│       │   │                           ├── controller/
│       │   │                           │   └── FlowGramTaskController.java
│       │   │                           ├── dto/
│       │   │                           │   ├── FlowGramErrorResponse.java
│       │   │                           │   ├── FlowGramTaskCancelResponse.java
│       │   │                           │   ├── FlowGramTaskReportResponse.java
│       │   │                           │   ├── FlowGramTaskResultResponse.java
│       │   │                           │   ├── FlowGramTaskRunRequest.java
│       │   │                           │   ├── FlowGramTaskRunResponse.java
│       │   │                           │   ├── FlowGramTaskValidateRequest.java
│       │   │                           │   ├── FlowGramTaskValidateResponse.java
│       │   │                           │   └── FlowGramTraceView.java
│       │   │                           ├── exception/
│       │   │                           │   ├── FlowGramAccessDeniedException.java
│       │   │                           │   ├── FlowGramApiException.java
│       │   │                           │   ├── FlowGramExceptionHandler.java
│       │   │                           │   └── FlowGramTaskNotFoundException.java
│       │   │                           ├── node/
│       │   │                           │   ├── FlowGramCodeNodeExecutor.java
│       │   │                           │   ├── FlowGramHttpNodeExecutor.java
│       │   │                           │   ├── FlowGramKnowledgeRetrieveNodeExecutor.java
│       │   │                           │   ├── FlowGramNodeValueResolver.java
│       │   │                           │   ├── FlowGramToolNodeExecutor.java
│       │   │                           │   └── FlowGramVariableNodeExecutor.java
│       │   │                           ├── security/
│       │   │                           │   ├── DefaultFlowGramAccessChecker.java
│       │   │                           │   ├── DefaultFlowGramCallerResolver.java
│       │   │                           │   ├── DefaultFlowGramTaskOwnershipStrategy.java
│       │   │                           │   ├── FlowGramAccessChecker.java
│       │   │                           │   ├── FlowGramAction.java
│       │   │                           │   ├── FlowGramCaller.java
│       │   │                           │   ├── FlowGramCallerResolver.java
│       │   │                           │   ├── FlowGramTaskOwnership.java
│       │   │                           │   └── FlowGramTaskOwnershipStrategy.java
│       │   │                           └── support/
│       │   │                               ├── FlowGramRuntimeFacade.java
│       │   │                               ├── FlowGramRuntimeTraceCollector.java
│       │   │                               ├── FlowGramStoredTask.java
│       │   │                               ├── FlowGramTaskStore.java
│       │   │                               ├── FlowGramTraceResponseEnricher.java
│       │   │                               ├── InMemoryFlowGramTaskStore.java
│       │   │                               ├── JdbcFlowGramTaskStore.java
│       │   │                               └── RegistryBackedFlowGramModelClientResolver.java
│       │   └── resources/
│       │       └── META-INF/
│       │           ├── spring/
│       │           │   └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│       │           └── spring.factories
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           └── ai4j/
│                               └── flowgram/
│                                   └── springboot/
│                                       ├── FlowGramJdbcTaskStoreAutoConfigurationTest.java
│                                       ├── FlowGramRuntimeTraceCollectorTest.java
│                                       ├── FlowGramTaskControllerIntegrationTest.java
│                                       ├── node/
│                                       │   ├── FlowGramBuiltinNodeExecutorTest.java
│                                       │   └── FlowGramKnowledgeRetrieveNodeExecutorTest.java
│                                       └── support/
│                                           └── JdbcFlowGramTaskStoreTest.java
├── ai4j-flowgram-webapp-demo/
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── README.md
│   ├── README.zh_CN.md
│   ├── index.html
│   ├── package.json
│   ├── rsbuild.config.ts
│   ├── src/
│   │   ├── app.tsx
│   │   ├── assets/
│   │   │   ├── icon-auto-layout.tsx
│   │   │   ├── icon-cancel.tsx
│   │   │   ├── icon-comment.tsx
│   │   │   ├── icon-minimap.tsx
│   │   │   ├── icon-mouse.tsx
│   │   │   ├── icon-pad.tsx
│   │   │   ├── icon-success.tsx
│   │   │   ├── icon-switch-line.tsx
│   │   │   └── icon-warning.tsx
│   │   ├── components/
│   │   │   ├── add-node/
│   │   │   │   ├── index.tsx
│   │   │   │   └── use-add-node.ts
│   │   │   ├── base-node/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── node-wrapper.tsx
│   │   │   │   ├── styles.tsx
│   │   │   │   └── utils.ts
│   │   │   ├── comment/
│   │   │   │   ├── components/
│   │   │   │   │   ├── blank-area.tsx
│   │   │   │   │   ├── border-area.tsx
│   │   │   │   │   ├── container.tsx
│   │   │   │   │   ├── content-drag-area.tsx
│   │   │   │   │   ├── drag-area.tsx
│   │   │   │   │   ├── editor.tsx
│   │   │   │   │   ├── index.css
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── more-button.tsx
│   │   │   │   │   ├── render.tsx
│   │   │   │   │   └── resize-area.tsx
│   │   │   │   ├── constant.ts
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── use-model.ts
│   │   │   │   │   ├── use-overflow.ts
│   │   │   │   │   ├── use-placeholder.ts
│   │   │   │   │   └── use-size.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── model.ts
│   │   │   │   └── type.ts
│   │   │   ├── group/
│   │   │   │   ├── color.ts
│   │   │   │   ├── components/
│   │   │   │   │   ├── background.tsx
│   │   │   │   │   ├── color.tsx
│   │   │   │   │   ├── header.tsx
│   │   │   │   │   ├── icon-group.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── node-render.tsx
│   │   │   │   │   ├── tips/
│   │   │   │   │   │   ├── global-store.ts
│   │   │   │   │   │   ├── icon-close.tsx
│   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   ├── is-mac-os.ts
│   │   │   │   │   │   ├── style.ts
│   │   │   │   │   │   └── use-control.ts
│   │   │   │   │   ├── title.tsx
│   │   │   │   │   ├── tools.tsx
│   │   │   │   │   └── ungroup.tsx
│   │   │   │   ├── constant.ts
│   │   │   │   ├── index.css
│   │   │   │   └── index.ts
│   │   │   ├── index.ts
│   │   │   ├── line-add-button/
│   │   │   │   ├── button.tsx
│   │   │   │   ├── index.less
│   │   │   │   ├── index.tsx
│   │   │   │   └── use-visible.ts
│   │   │   ├── node-menu/
│   │   │   │   └── index.tsx
│   │   │   ├── node-panel/
│   │   │   │   ├── index.less
│   │   │   │   ├── index.tsx
│   │   │   │   ├── node-list.tsx
│   │   │   │   └── node-placeholder.tsx
│   │   │   ├── problem-panel/
│   │   │   │   ├── index.ts
│   │   │   │   ├── problem-panel.tsx
│   │   │   │   └── use-watch-validate.ts
│   │   │   ├── selector-box-popover/
│   │   │   │   └── index.tsx
│   │   │   ├── sidebar/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── node-form-panel.tsx
│   │   │   │   └── sidebar-node-renderer.tsx
│   │   │   ├── testrun/
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── use-fields.ts
│   │   │   │   │   ├── use-form-meta.ts
│   │   │   │   │   └── use-sync-default.ts
│   │   │   │   ├── json-value-editor/
│   │   │   │   │   └── index.tsx
│   │   │   │   ├── node-status-bar/
│   │   │   │   │   ├── group/
│   │   │   │   │   │   ├── index.module.less
│   │   │   │   │   │   └── index.tsx
│   │   │   │   │   ├── header/
│   │   │   │   │   │   ├── index.module.less
│   │   │   │   │   │   └── index.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── render/
│   │   │   │   │   │   ├── index.module.less
│   │   │   │   │   │   └── index.tsx
│   │   │   │   │   └── viewer/
│   │   │   │   │       ├── index.module.less
│   │   │   │   │       └── index.tsx
│   │   │   │   ├── testrun-button/
│   │   │   │   │   ├── index.module.less
│   │   │   │   │   └── index.tsx
│   │   │   │   ├── testrun-form/
│   │   │   │   │   ├── index.module.less
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── type.ts
│   │   │   │   ├── testrun-json-input/
│   │   │   │   │   ├── index.module.less
│   │   │   │   │   └── index.tsx
│   │   │   │   ├── testrun-panel/
│   │   │   │   │   ├── index.module.less
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── test-run-panel.tsx
│   │   │   │   └── trace-panel/
│   │   │   │       ├── index.module.less
│   │   │   │       └── index.tsx
│   │   │   └── tools/
│   │   │       ├── auto-layout.tsx
│   │   │       ├── comment.tsx
│   │   │       ├── download.tsx
│   │   │       ├── fit-view.tsx
│   │   │       ├── index.tsx
│   │   │       ├── interactive.tsx
│   │   │       ├── minimap-switch.tsx
│   │   │       ├── minimap.tsx
│   │   │       ├── mouse-pad-selector.less
│   │   │       ├── mouse-pad-selector.tsx
│   │   │       ├── readonly.tsx
│   │   │       ├── save.tsx
│   │   │       ├── styles.tsx
│   │   │       ├── switch-line.tsx
│   │   │       └── zoom-select.tsx
│   │   ├── context/
│   │   │   ├── index.ts
│   │   │   ├── node-render-context.ts
│   │   │   └── sidebar-context.ts
│   │   ├── data/
│   │   │   └── workflow-templates.ts
│   │   ├── editor.tsx
│   │   ├── form-components/
│   │   │   ├── feedback.tsx
│   │   │   ├── form-content/
│   │   │   │   ├── index.tsx
│   │   │   │   └── styles.tsx
│   │   │   ├── form-header/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── styles.tsx
│   │   │   │   ├── title-input.tsx
│   │   │   │   └── utils.tsx
│   │   │   ├── form-inputs/
│   │   │   │   ├── index.tsx
│   │   │   │   └── styles.tsx
│   │   │   ├── form-item/
│   │   │   │   ├── index.css
│   │   │   │   └── index.tsx
│   │   │   └── index.ts
│   │   ├── hooks/
│   │   │   ├── index.ts
│   │   │   ├── use-editor-props.tsx
│   │   │   ├── use-is-sidebar.ts
│   │   │   ├── use-node-render-context.ts
│   │   │   └── use-port-click.ts
│   │   ├── index.ts
│   │   ├── initial-data.ts
│   │   ├── nodes/
│   │   │   ├── block-end/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── block-start/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── break/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── code/
│   │   │   │   ├── components/
│   │   │   │   │   ├── code.tsx
│   │   │   │   │   ├── inputs.tsx
│   │   │   │   │   └── outputs.tsx
│   │   │   │   ├── form-meta.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   └── types.tsx
│   │   │   ├── comment/
│   │   │   │   └── index.tsx
│   │   │   ├── condition/
│   │   │   │   ├── condition-inputs/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styles.tsx
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── constants.ts
│   │   │   ├── continue/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── default-form-meta.tsx
│   │   │   ├── end/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── group/
│   │   │   │   └── index.tsx
│   │   │   ├── http/
│   │   │   │   ├── components/
│   │   │   │   │   ├── api.tsx
│   │   │   │   │   ├── body.tsx
│   │   │   │   │   ├── headers.tsx
│   │   │   │   │   ├── params.tsx
│   │   │   │   │   └── timeout.tsx
│   │   │   │   ├── form-meta.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   └── types.tsx
│   │   │   ├── index.ts
│   │   │   ├── knowledge/
│   │   │   │   └── index.tsx
│   │   │   ├── llm/
│   │   │   │   └── index.ts
│   │   │   ├── loop/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── start/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── tool/
│   │   │   │   └── index.tsx
│   │   │   └── variable/
│   │   │       ├── form-meta.tsx
│   │   │       ├── index.tsx
│   │   │       ├── output-schema.ts
│   │   │       └── types.tsx
│   │   ├── plugins/
│   │   │   ├── context-menu-plugin/
│   │   │   │   ├── context-menu-layer.tsx
│   │   │   │   ├── context-menu-plugin.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.ts
│   │   │   ├── panel-manager-plugin/
│   │   │   │   ├── constants.ts
│   │   │   │   ├── hooks.ts
│   │   │   │   └── index.tsx
│   │   │   ├── runtime-plugin/
│   │   │   │   ├── client/
│   │   │   │   │   ├── base-client.ts
│   │   │   │   │   ├── browser-client/
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── server-client/
│   │   │   │   │       ├── constant.ts
│   │   │   │   │       ├── index.ts
│   │   │   │   │       └── type.ts
│   │   │   │   ├── create-runtime-plugin.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── runtime-service/
│   │   │   │   │   └── index.ts
│   │   │   │   ├── trace.ts
│   │   │   │   └── type.ts
│   │   │   └── variable-panel-plugin/
│   │   │       ├── components/
│   │   │       │   ├── full-variable-list.tsx
│   │   │       │   ├── global-variable-editor.tsx
│   │   │       │   ├── index.module.less
│   │   │       │   └── variable-panel.tsx
│   │   │       ├── index.ts
│   │   │       ├── variable-panel-layer.tsx
│   │   │       └── variable-panel-plugin.ts
│   │   ├── services/
│   │   │   ├── custom-service.ts
│   │   │   ├── index.ts
│   │   │   └── validate-service.ts
│   │   ├── shortcuts/
│   │   │   ├── collapse/
│   │   │   │   └── index.ts
│   │   │   ├── constants.ts
│   │   │   ├── copy/
│   │   │   │   └── index.ts
│   │   │   ├── delete/
│   │   │   │   └── index.ts
│   │   │   ├── expand/
│   │   │   │   └── index.ts
│   │   │   ├── index.ts
│   │   │   ├── paste/
│   │   │   │   ├── index.ts
│   │   │   │   ├── traverse.ts
│   │   │   │   └── unique-workflow.ts
│   │   │   ├── select-all/
│   │   │   │   └── index.ts
│   │   │   ├── shortcuts.ts
│   │   │   ├── type.ts
│   │   │   ├── zoom-in/
│   │   │   │   └── index.ts
│   │   │   └── zoom-out/
│   │   │       └── index.ts
│   │   ├── styles/
│   │   │   └── index.css
│   │   ├── type.d.ts
│   │   ├── typings/
│   │   │   ├── index.ts
│   │   │   ├── json-schema.ts
│   │   │   └── node.ts
│   │   ├── utils/
│   │   │   ├── backend-workflow.ts
│   │   │   ├── can-contain-node.ts
│   │   │   ├── index.ts
│   │   │   ├── on-drag-line-end.ts
│   │   │   └── toggle-loop-expanded.ts
│   │   └── workbench/
│   │       ├── runtime-hooks.ts
│   │       ├── workbench-shell.tsx
│   │       ├── workbench-sidebar.tsx
│   │       └── workbench-toolbar.tsx
│   └── tsconfig.json
├── ai4j-spring-boot-starter/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── github/
│       │   │           └── lnyocly/
│       │   │               └── ai4j/
│       │   │                   ├── AgentFlowProperties.java
│       │   │                   ├── AgentFlowRegistry.java
│       │   │                   ├── AiConfigAutoConfiguration.java
│       │   │                   ├── AiConfigProperties.java
│       │   │                   ├── AiPlatformProperties.java
│       │   │                   ├── BaichuanConfigProperties.java
│       │   │                   ├── DashScopeConfigProperties.java
│       │   │                   ├── DeepSeekConfigProperties.java
│       │   │                   ├── DoubaoConfigProperties.java
│       │   │                   ├── HunyuanConfigProperties.java
│       │   │                   ├── JinaConfigProperties.java
│       │   │                   ├── LingyiConfigProperties.java
│       │   │                   ├── MilvusConfigProperties.java
│       │   │                   ├── MinimaxConfigProperties.java
│       │   │                   ├── MoonshotConfigProperties.java
│       │   │                   ├── OkHttpConfigProperties.java
│       │   │                   ├── OllamaConfigProperties.java
│       │   │                   ├── OpenAiConfigProperties.java
│       │   │                   ├── PgVectorConfigProperties.java
│       │   │                   ├── PineconeConfigProperties.java
│       │   │                   ├── QdrantConfigProperties.java
│       │   │                   ├── SearXNGConfigProperties.java
│       │   │                   └── ZhipuConfigProperties.java
│       │   └── resources/
│       │       └── META-INF/
│       │           ├── spring/
│       │           │   └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│       │           └── spring.factories
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           └── ai4j/
│                               └── AgentFlowAutoConfigurationTest.java
├── docs-site/
│   ├── .gitignore
│   ├── README.md
│   ├── docusaurus.config.ts
│   ├── i18n/
│   │   └── zh-Hans/
│   │       ├── code.json
│   │       ├── docusaurus-plugin-content-docs/
│   │       │   ├── current/
│   │       │   │   ├── agent/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   ├── agent-teams.md
│   │       │   │   │   ├── codeact-custom-sandbox.md
│   │       │   │   │   ├── codeact-runtime.md
│   │       │   │   │   ├── coding-agent-cli.md
│   │       │   │   │   ├── coding-agent-command-reference.md
│   │       │   │   │   ├── custom-agent-development.md
│   │       │   │   │   ├── memory-management.md
│   │       │   │   │   ├── model-client-selection.md
│   │       │   │   │   ├── multi-provider-profiles.md
│   │       │   │   │   ├── overview.md
│   │       │   │   │   ├── provider-config-examples.md
│   │       │   │   │   ├── reference-core-classes.md
│   │       │   │   │   ├── runtime-implementations.md
│   │       │   │   │   ├── subagent-handoff-policy.md
│   │       │   │   │   ├── system-prompt-vs-instructions.md
│   │       │   │   │   ├── trace-observability.md
│   │       │   │   │   ├── weather-workflow-cookbook.md
│   │       │   │   │   └── workflow-stategraph.md
│   │       │   │   ├── ai-basics/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   ├── chat/
│   │       │   │   │   │   ├── _category_.json
│   │       │   │   │   │   ├── multimodal.md
│   │       │   │   │   │   ├── non-stream.md
│   │       │   │   │   │   ├── stream.md
│   │       │   │   │   │   └── tool-calling.md
│   │       │   │   │   ├── enhancements/
│   │       │   │   │   │   ├── _category_.json
│   │       │   │   │   │   ├── pinecone-rag-workflow.md
│   │       │   │   │   │   ├── searxng-enhancement.md
│   │       │   │   │   │   └── spi-http-stack.md
│   │       │   │   │   ├── overview.md
│   │       │   │   │   ├── platform-adaptation.md
│   │       │   │   │   ├── responses/
│   │       │   │   │   │   ├── _category_.json
│   │       │   │   │   │   ├── chat-vs-responses.md
│   │       │   │   │   │   ├── non-stream.md
│   │       │   │   │   │   └── stream-events.md
│   │       │   │   │   └── services/
│   │       │   │   │       ├── _category_.json
│   │       │   │   │       ├── audio.md
│   │       │   │   │       ├── embedding.md
│   │       │   │   │       ├── image-generation.md
│   │       │   │   │       └── realtime.md
│   │       │   │   ├── core-sdk/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   ├── agentflow-protocol-mapping.md
│   │       │   │   │   ├── agentflow.md
│   │       │   │   │   ├── audio.md
│   │       │   │   │   ├── chat/
│   │       │   │   │   │   ├── multimodal.md
│   │       │   │   │   │   ├── non-stream.md
│   │       │   │   │   │   ├── stream.md
│   │       │   │   │   │   └── tool-calling.md
│   │       │   │   │   ├── embedding.md
│   │       │   │   │   ├── image-generation.md
│   │       │   │   │   ├── overview.md
│   │       │   │   │   ├── pinecone-rag-workflow.md
│   │       │   │   │   ├── platform-service-matrix.md
│   │       │   │   │   ├── realtime.md
│   │       │   │   │   ├── responses/
│   │       │   │   │   │   ├── chat-vs-responses.md
│   │       │   │   │   │   ├── non-stream.md
│   │       │   │   │   │   └── stream-events.md
│   │       │   │   │   ├── searxng-enhancement.md
│   │       │   │   │   └── spi-http-stack.md
│   │       │   │   ├── deploy/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   └── cloudflare-pages.md
│   │       │   │   ├── getting-started/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   ├── chat-and-responses-guide.md
│   │       │   │   │   ├── coding-agent-cli-quickstart.md
│   │       │   │   │   ├── installation.md
│   │       │   │   │   ├── multimodal-and-function-call.md
│   │       │   │   │   ├── platforms-and-service-matrix.md
│   │       │   │   │   ├── quickstart-ollama.md
│   │       │   │   │   ├── quickstart-openai-jdk8.md
│   │       │   │   │   ├── quickstart-springboot.md
│   │       │   │   │   └── troubleshooting.md
│   │       │   │   ├── guides/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   ├── blog-migration-map.md
│   │       │   │   │   ├── deepseek-stream-search-rag.md
│   │       │   │   │   ├── pinecone-vector-workflow.md
│   │       │   │   │   ├── rag-legal-assistant.md
│   │       │   │   │   ├── searxng-web-search.md
│   │       │   │   │   └── spi-dispatcher-connectionpool.md
│   │       │   │   ├── intro.md
│   │       │   │   └── mcp/
│   │       │   │       ├── _category_.json
│   │       │   │       ├── build-your-mcp-server.md
│   │       │   │       ├── client-integration.md
│   │       │   │       ├── gateway-management.md
│   │       │   │       ├── mcp-agent-end-to-end.md
│   │       │   │       ├── mysql-dynamic-datasource.md
│   │       │   │       ├── overview.md
│   │       │   │       ├── third-party-mcp-integration.md
│   │       │   │       ├── tool-exposure-semantics.md
│   │       │   │       └── transport-types.md
│   │       │   └── current.json
│   │       └── docusaurus-theme-classic/
│   │           ├── footer.json
│   │           └── navbar.json
│   ├── package.json
│   ├── scripts/
│   │   └── generate_agent_teams_api_docs.py
│   ├── sidebars.ts
│   ├── src/
│   │   ├── components/
│   │   │   └── HomepageFeatures/
│   │   │       ├── index.tsx
│   │   │       └── styles.module.css
│   │   ├── css/
│   │   │   └── custom.css
│   │   ├── pages/
│   │   │   ├── index.module.css
│   │   │   └── index.tsx
│   │   └── theme/
│   │       └── NotFound/
│   │           └── Content/
│   │               └── index.tsx
│   ├── static/
│   │   ├── .nojekyll
│   │   ├── install.ps1
│   │   └── install.sh
│   └── tsconfig.json
└── pom.xml

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4

[*.md]
trim_trailing_whitespace = false

================================================
FILE: .github/workflows/docs-build.yml
================================================
name: docs-build

on:
  pull_request:
    paths:
      - 'docs-site/**'
      - '.github/workflows/docs-build.yml'
  push:
    branches: [main, dev]
    paths:
      - 'docs-site/**'
      - '.github/workflows/docs-build.yml'

jobs:
  build:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: docs-site

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          cache-dependency-path: docs-site/package-lock.json

      - name: Install dependencies
        run: npm ci

      - name: Build docs
        run: npm run build


================================================
FILE: .github/workflows/docs-pages.yml
================================================
name: docs-pages

on:
  push:
    branches: [main]
    paths:
      - 'docs-site/**'
      - '.github/workflows/docs-pages.yml'
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: docs-pages
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: docs-site
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          cache-dependency-path: docs-site/package-lock.json

      - name: Configure Pages
        uses: actions/configure-pages@v5

      - name: Install dependencies
        run: npm ci

      - name: Build docs
        env:
          GITHUB_PAGES: 'true'
        run: npm run build

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: docs-site/build

  deploy:
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4


================================================
FILE: .gitignore
================================================
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr

### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/

### Local tooling ###
.claude/
AGENTS.md
node_modules/
dist/
.rsbuild/
.turbo/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

### Scratch / temp ###
*.class
.tmp*/
.tmp*
tmp/
tmp-*/
tmp-*.png
tmp-*.txt
tmp-*.log

**/.flattened-pom.xml

### Mac OS ###
.DS_Store
/.idea/
/ai4j/.gitignore
/ai4j/src/main/resources/新建文本文档 (2).txt
/ai4j-spring-boot-stater/.gitignore
.ai4j/
.docs/
docs/
APIResponse.md
AGENT.md
ai4j-release-package.log
javadoc-ai4j.log


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

================================================
FILE: README-EN.md
================================================
<p align="center">
  <img src="https://capsule-render.vercel.app/api?type=waving&color=0:6A5ACD,100:2E86C1&height=180&section=header&text=ai4j&fontSize=46&fontColor=ffffff&animation=fadeIn&desc=Java%20AI%20Agentic%20SDK%20for%20JDK%208%2B&descAlignY=68" alt="ai4j banner" />
</p>

<p align="center">
  <a href="https://search.maven.org/artifact/io.github.lnyo-cly/ai4j">
    <img src="https://img.shields.io/maven-central/v/io.github.lnyo-cly/ai4j?color=2E86C1&label=Maven%20Central" alt="Maven Central" />
  </a>
  <a href="https://lnyo-cly.github.io/ai4j/">
    <img src="https://img.shields.io/badge/Docs-GitHub%20Pages-0A7EA4" alt="Docs" />
  </a>
  <a href="https://www.apache.org/licenses/LICENSE-2.0.txt">
    <img src="https://img.shields.io/badge/License-Apache%202.0-1F6FEB" alt="License" />
  </a>
  <img src="https://img.shields.io/badge/JDK-8%2B-2EA043" alt="JDK 8+" />
  <img src="https://img.shields.io/badge/Agentic-Enabled-6F42C1" alt="Agentic Enabled" />
  <img src="https://img.shields.io/badge/MCP-Supported-0F766E" alt="MCP Supported" />
  <img src="https://img.shields.io/badge/RAG-Built--in-B45309" alt="RAG Built-in" />
  <img src="https://img.shields.io/badge/CLI%20%2F%20TUI%20%2F%20ACP-Built--in-475569" alt="CLI TUI ACP Built-in" />
</p>

# ai4j
A Java AI Agentic development toolkit for JDK 8+, combining foundational AI capabilities with higher-level agent development capabilities.  
It covers multi-provider model access, unified I/O, Tool Calling, MCP, RAG, unified `VectorStore`, ChatMemory, agent runtime, coding agent, CLI / TUI / ACP, FlowGram integration, and integration with published AgentFlow endpoints such as Dify, Coze, and n8n, helping Java applications grow from basic model integration to more complete agentic application development.

This repository has evolved into a multi-module SDK. In addition to the core `ai4j` module, it now provides `ai4j-agent`, `ai4j-coding`, `ai4j-cli`, `ai4j-spring-boot-starter`, `ai4j-flowgram-spring-boot-starter`, and `ai4j-bom`. If you only need the basic LLM integration layer, start with `ai4j`. If you need agent runtime, coding agent, CLI / ACP, Spring Boot, or FlowGram integration, add the corresponding modules.

## Positioning Compared with Common Java AI Options

| Option | Java baseline | Application style | Primary focus |
| --- | --- | --- | --- |
| `ai4j` | `JDK 8+` | Plain Java / Spring | Unified model access, Tool / MCP / RAG, agent runtime, coding agent, CLI / TUI / ACP |
| `Spring AI` | `Java 17+` | `Spring Boot 3.x` | Spring-native AI integration, model access, Tool Calling, MCP, and RAG |
| `Spring AI Alibaba` | `Java 17+` | `Spring Boot 3.x` | Spring and Alibaba Cloud AI ecosystem integration |
| `LangChain4j` | `Java 17+` | Plain Java / Spring / Quarkus and more | General Java abstractions for LLM, agent, and RAG integration, plus AI Services |

## Supported platforms
+ OpenAi
+ Jina (Rerank / Jina-compatible Rerank)
+ Zhipu
+ DeepSeek
+ Moonshot
+ Tencent Hunyuan
+ Lingyi AI
+ Ollama
+ MiniMax
+ Baichuan

## Supported services
+ Chat Completions(streaming and non-streaming)
+ Responses
+ Embedding
+ Rerank
+ Audio
+ Image
+ Realtime

## Supported AgentFlow / hosted workflow platforms
+ Dify (chat / workflow)
+ Coze (chat / workflow)
+ n8n (webhook workflow)

## Features
+ Supports Spring and ordinary Java applications. Supports applications above Java 8.
+ Multi-platform and multi-service.
+ Provides `AgentFlow` support for integrating published Agent / Workflow endpoints from Dify, Coze, and n8n.
+ Provides `ai4j-agent` as the general agent runtime, with ReAct, subagents, agent teams, memory, tracing, and tool loop support.
+ Built-in Coding Agent CLI / TUI with interactive repository sessions, provider profiles, workspace model override, and session/process management.
+ Provides `ai4j-coding` as the coding agent runtime, with workspace-aware tools, outer loop, checkpoint compaction, subagent, and team collaboration support.
+ Provides `ai4j-flowgram-spring-boot-starter` for integrating FlowGram workflows and trace in Spring Boot applications.
+ Provides `ai4j-bom` for version alignment across multiple ai4j modules.
+ Unified input and output.
+ Unified error handling.
+ Supports streaming output. Supports streaming output of function call parameters.
+ Easily use Tool Calls.
+ Supports simultaneous calls of multiple functions (Zhipu does not support this).
+ Supports stream_options, and directly obtains statistical token usage through streaming output.
+ Supports RAG. Built-in vector database support: Pinecone.
+ Uses Tika to read files.
+ Token statistics`TikTokensUtil.java`


## Tutorial documents
+ [Quick access to Spring Boot, access to streaming and non-streaming and function calls.](http://t.csdnimg.cn/iuIAW)
+ [Quick access to open source large models such as qwen2.5 and llama3.1 on the Ollama platform in Java.](https://blog.csdn.net/qq_35650513/article/details/142408092?spm=1001.2014.3001.5501)
+ [Build a legal AI assistant in Java and quickly implement RAG applications.](https://blog.csdn.net/qq_35650513/article/details/142568177?fromshare=blogdetail&sharetype=blogdetail&sharerId=142568177&sharerefer=PC&sharesource=qq_35650513&sharefrom=from_link)

## Coding Agent CLI / TUI

AI4J now includes `ai4j-cli`, which can be used directly as a local coding agent. Current capabilities include:

+ one-shot and persistent sessions
+ CLI and TUI interaction modes
+ provider profile persistence
+ workspace-level model override
+ subagent and agent team collaboration
+ session persistence, resume, fork, history, tree, events, replay
+ team board, team messages, and team resume for collaboration visibility
+ process management and buffered logs

### Install

```bash
curl -fsSL https://lnyo-cly.github.io/ai4j/install.sh | sh
```

```powershell
irm https://lnyo-cly.github.io/ai4j/install.ps1 | iex
```

The installer downloads `ai4j-cli` from Maven Central and creates the `ai4j` command. Java 8+ must already be installed on the machine.

### one-shot example

```powershell
ai4j code `
  --provider openai `
  --protocol responses `
  --model gpt-5-mini `
  --prompt "Read README and summarize the project structure"
```

### interactive CLI example

```powershell
ai4j code `
  --provider zhipu `
  --protocol chat `
  --model glm-4.7 `
  --base-url https://open.bigmodel.cn/api/coding/paas/v4 `
  --workspace .
```

### TUI example

```powershell
ai4j tui `
  --provider zhipu `
  --protocol chat `
  --model glm-4.7 `
  --base-url https://open.bigmodel.cn/api/coding/paas/v4 `
  --workspace .
```

### ACP example

```powershell
ai4j acp `
  --provider openai `
  --protocol responses `
  --model gpt-5-mini `
  --workspace .
```

### Build from source (optional)

```powershell
mvn -pl ai4j-cli -am -DskipTests package
```

Artifact:

```text
ai4j-cli/target/ai4j-cli-<version>-jar-with-dependencies.jar
```

If you want to run the locally built artifact directly:

```powershell
java -jar .\ai4j-cli\target\ai4j-cli-<version>-jar-with-dependencies.jar code --help
```

### Current protocol rules

The CLI currently exposes only two protocol families:

+ `chat`
+ `responses`

If `--protocol` is omitted, the CLI resolves a default locally from provider/baseUrl:

+ `openai` + official OpenAI host -> `responses`
+ `openai` + custom compatible `baseUrl` -> `chat`
+ `doubao` / `dashscope` -> `responses`
+ other providers -> `chat`

Notes:

+ `auto` is no longer exposed to users
+ legacy `auto` values in existing config files are normalized to explicit protocols on load

### provider profile locations

+ global config: `~/.ai4j/providers.json`
+ workspace config: `<workspace>/.ai4j/workspace.json`

Recommended workflow:

+ keep reusable long-term runtime profiles in the global config
+ let each workspace reference one `activeProfile`
+ use workspace `modelOverride` for temporary model switching

### Common commands

+ `/providers`
+ `/provider`
+ `/provider use <name>`
+ `/provider save <name>`
+ `/provider add <name> --provider <name> [--protocol <chat|responses>] [--model <name>] [--base-url <url>] [--api-key <key>]`
+ `/provider edit <name> [--provider <name>] [--protocol <chat|responses>] [--model <name>|--clear-model] [--base-url <url>|--clear-base-url] [--api-key <key>|--clear-api-key]`
+ `/provider default <name|clear>`
+ `/provider remove <name>`
+ `/model`
+ `/model <name>`
+ `/model reset`
+ `/stream [on|off]`
+ `/processes`
+ `/process status|follow|logs|write|stop ...`
+ `/resume <id>` / `/load <id>` / `/fork ...`

### Documentation entry points

+ [Coding Agent CLI Quickstart](docs-site/docs/getting-started/coding-agent-cli-quickstart.md)
+ [Coding Agent CLI and TUI](docs-site/docs/agent/coding-agent-cli.md)
+ [Multi-Provider Profiles](docs-site/docs/agent/multi-provider-profiles.md)
+ [Coding Agent Command Reference](docs-site/docs/agent/coding-agent-command-reference.md)
+ [Provider Configuration Examples](docs-site/docs/agent/provider-config-examples.md)

## Other support
+ [[Low-cost transit platform] Low-cost ApiKey - Limited-time special offer 0.7:1 - Supports the latest o1 model.](https://api.trovebox.online/)

# Quick start
## Import
### Module selection
+ Use `ai4j` for the core LLM / Tool Call / MCP / RAG capabilities
+ Use `ai4j-agent` for the general agent runtime
+ Use `ai4j-coding` for coding agent, workspace tools, and outer loop
+ Use `ai4j-cli` for the local CLI / TUI / ACP host
+ Use `ai4j-spring-boot-starter` for Spring Boot auto-configuration
+ Use `ai4j-flowgram-spring-boot-starter` for FlowGram workflow integration
+ Use `ai4j-bom` when you want version alignment across multiple modules

### Gradle
```groovy
implementation platform("io.github.lnyo-cly:ai4j-bom:${project.version}")
implementation "io.github.lnyo-cly:ai4j"
implementation "io.github.lnyo-cly:ai4j-agent"
```

```groovy
implementation group: 'io.github.lnyo-cly', name: 'ai4j', version: '${project.version}'
```

```groovy
implementation group: 'io.github.lnyo-cly', name: 'ai4j-spring-boot-starter', version: '${project.version}'
```


### Maven
```xml
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.github.lnyo-cly</groupId>
            <artifactId>ai4j-bom</artifactId>
            <version>${project.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
```

```xml
<!-- Recommended for multi-module usage -->
<dependency>
    <groupId>io.github.lnyo-cly</groupId>
    <artifactId>ai4j-agent</artifactId>
</dependency>

<dependency>
    <groupId>io.github.lnyo-cly</groupId>
    <artifactId>ai4j-coding</artifactId>
</dependency>
```

```xml
<!-- Non-Spring application -->
<dependency>
    <groupId>io.github.lnyo-cly</groupId>
    <artifactId>ai4j</artifactId>
    <version>${project.version}</version>
</dependency>

```
```xml
<!-- Spring application -->
<dependency>
    <groupId>io.github.lnyo-cly</groupId>
    <artifactId>ai4j-spring-boot-starter</artifactId>
    <version>${project.version}</version>
</dependency>
```

## Obtain AI service instance

### Obtaining without Spring
```java
    public void test_init(){
        OpenAiConfig openAiConfig = new OpenAiConfig();

        Configuration configuration = new Configuration();
        configuration.setOpenAiConfig(openAiConfig);

        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);

        OkHttpClient okHttpClient = new OkHttpClient
                .Builder()
                .addInterceptor(httpLoggingInterceptor)
                .addInterceptor(new ErrorInterceptor())
                .connectTimeout(300, TimeUnit.SECONDS)
                .writeTimeout(300, TimeUnit.SECONDS)
                .readTimeout(300, TimeUnit.SECONDS)
                .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1",10809)))
                .build();
        configuration.setOkHttpClient(okHttpClient);

        AiService aiService = new AiService(configuration);

        embeddingService = aiService.getEmbeddingService(PlatformType.OPENAI);
        chatService = aiService.getChatService(PlatformType.getPlatform("OPENAI"));

    }
```
### Obtaining with Spring
```yml
# Domestic access usually requires a proxy by default.
ai:
  openai:
    api-key: "api-key"
  okhttp:
    proxy-port: 10809
    proxy-url: "127.0.0.1"
  zhipu:
    api-key: "xxx"
  #other...
```

```java
// Inject Ai service
@Autowired
private AiService aiService;

// Obtain the required service instance
IChatService chatService = aiService.getChatService(PlatformType.OPENAI);
IEmbeddingService embeddingService = aiService.getEmbeddingService(PlatformType.OPENAI);
// ......
```

## Chat service

### Synchronous request call
```java

public void test_chat() throws Exception {
    // Obtain chat service instance
    IChatService chatService = aiService.getChatService(PlatformType.OPENAI);

    // Build request parameters
    ChatCompletion chatCompletion = ChatCompletion.builder()
            .model("gpt-4o-mini")
            .message(ChatMessage.withUser("鲁迅为什么打周树人"))
            .build();

    // Send dialogue request
    ChatCompletionResponse response = chatService.chatCompletion(chatCompletion);

    System.out.println(response);
}

```

### Streaming call
```java
public void test_chat_stream() throws Exception {
    // Obtain chat service instance
    IChatService chatService = aiService.getChatService(PlatformType.OPENAI);

    // Construct request parameters
    ChatCompletion chatCompletion = ChatCompletion.builder()
            .model("gpt-4o-mini")
            .message(ChatMessage.withUser("查询北京明天的天气"))
            .functions("queryWeather")
            .build();


    // Construct listener
    SseListener sseListener = new SseListener() {
        @Override
        protected void send() {
            System.out.println(this.getCurrStr());
        }
    };
    // Display function parameters. Default is not to display.
    sseListener.setShowToolArgs(true);

    // Send SSE request
    chatService.chatCompletionStream(chatCompletion, sseListener);

    System.out.println(sseListener.getOutput());

}
```

### Image recognition

```java
public void test_chat_image() throws Exception {
    // Obtain chat service instance
    IChatService chatService = aiService.getChatService(PlatformType.OPENAI);

    // Build request parameters
    ChatCompletion chatCompletion = ChatCompletion.builder()
            .model("gpt-4o-mini")
            .message(ChatMessage.withUser("图片中有什么东西", "https://cn.bing.com/images/search?view=detailV2&ccid=r0OnuYkv&id=9A07DE578F6ED50DB59DFEA5C675AC71845A6FC9&thid=OIP.r0OnuYkvsbqBrYk3kUT53AHaKX&mediaurl=https%3a%2f%2fimg.zcool.cn%2fcommunity%2f0104c15cd45b49a80121416816f1ec.jpg%401280w_1l_2o_100sh.jpg&exph=1792&expw=1280&q=%e5%b0%8f%e7%8c%ab%e5%9b%be%e7%89%87&simid=607987191780608963&FORM=IRPRST&ck=12127C1696CF374CB9D0F09AE99AFE69&selectedIndex=2&itb=0&qpvt=%e5%b0%8f%e7%8c%ab%e5%9b%be%e7%89%87"))
            .build();

    // Send dialogue request
    ChatCompletionResponse response = chatService.chatCompletion(chatCompletion);

    System.out.println(response);
}
```

### Function call

```java
public void test_chat_tool_call() throws Exception {
    // Obtain chat service instance
    IChatService chatService = aiService.getChatService(PlatformType.OPENAI);

    // Build request parameters
    ChatCompletion chatCompletion = ChatCompletion.builder()
            .model("gpt-4o-mini")
            .message(ChatMessage.withUser("今天北京天气怎么样"))
            .functions("queryWeather")
            .build();

    // Send dialogue request
    ChatCompletionResponse response = chatService.chatCompletion(chatCompletion);

    System.out.println(response);
}
```
#### Define function
```java
@FunctionCall(name = "queryWeather", description = "查询目标地点的天气预报")
public class QueryWeatherFunction implements Function<QueryWeatherFunction.Request, String> {

    @Data
    @FunctionRequest
    public static class Request{
        @FunctionParameter(description = "需要查询天气的目标位置, 可以是城市中文名、城市拼音/英文名、省市名称组合、IP 地址、经纬度")
        private String location;
        @FunctionParameter(description = "需要查询未来天气的天数, 最多15日")
        private int days = 15;
        @FunctionParameter(description = "预报的天气类型,daily表示预报多天天气、hourly表示预测当天24天气、now为当前天气实况")
        private Type type;
    }

    public enum Type{
        daily,
        hourly,
        now
    }

    @Override
    public String apply(Request request) {
        final String key = "";

        String url = String.format("https://api.seniverse.com/v3/weather/%s.json?key=%s&location=%s&days=%d",
                request.type.name(),
                key,
                request.location,
                request.days);


        OkHttpClient client = new OkHttpClient();

        okhttp3.Request http = new okhttp3.Request.Builder()
                .url(url)
                .get()
                .build();

        try (Response response = client.newCall(http).execute()) {
            if (response.isSuccessful()) {
                // 解析响应体
                return response.body() != null ? response.body().string() : "";
            } else {
                return "获取天气失败 当前天气未知";
            }
        } catch (Exception e) {
            // 处理异常
            e.printStackTrace();
            return "获取天气失败 当前天气未知";
        }
    }

}
```

## Embedding service

```java
public void test_embed() throws Exception {
    // Obtain embedding service instance
    IEmbeddingService embeddingService = aiService.getEmbeddingService(PlatformType.OPENAI);

    // Build request parameters
    Embedding embeddingReq = Embedding.builder().input("1+1").build();

    // Send embedding request
    EmbeddingResponse embeddingResp = embeddingService.embedding(embeddingReq);

    System.out.println(embeddingResp);
}
```

## RAG
### Configure vector database
```yml
ai:
  vector:
    pinecone:
      url: ""
      key: ""
```
### Obtain instance
```java
@Autowired
private PineconeService pineconeService;
```
### Insert into vector database
```java
public void test_insert_vector_store() throws Exception {
    // Obtain embedding service instance
    IEmbeddingService embeddingService = aiService.getEmbeddingService(PlatformType.OPENAI);

    // Read file content using Tika
    String fileContent = TikaUtil.parseFile(new File("D:\\data\\test\\test.txt"));

    // Split text content
    RecursiveCharacterTextSplitter recursiveCharacterTextSplitter = new RecursiveCharacterTextSplitter(1000, 200);
    List<String> contentList = recursiveCharacterTextSplitter.splitText(fileContent);

    // Convert to vector
    Embedding build = Embedding.builder()
            .input(contentList)
            .model("text-embedding-3-small")
            .build();
    EmbeddingResponse embedding = embeddingService.embedding(build);
    List<List<Float>> vectors = embedding.getData().stream().map(EmbeddingObject::getEmbedding).collect(Collectors.toList());
    VertorDataEntity vertorDataEntity = new VertorDataEntity();
    vertorDataEntity.setVector(vectors);
    vertorDataEntity.setContent(contentList);

    // Vector storage
    Integer count = pineconeService.insert(vertorDataEntity, "userId");

}
```
### Query from vector database
```java
public void test_query_vector_store() throws Exception {
    // // Obtain embedding service instance
    IEmbeddingService embeddingService = aiService.getEmbeddingService(PlatformType.OPENAI);

    // Build the question to be queried and convert it to a vector
    Embedding build = Embedding.builder()
            .input("question")
            .model("text-embedding-3-small")
            .build();
    EmbeddingResponse embedding = embeddingService.embedding(build);
    List<Float> question = embedding.getData().get(0).getEmbedding();

    // Build the query object for the vector database
    PineconeQuery pineconeQueryReq = PineconeQuery.builder()
            .namespace("userId")
            .vector(question)
            .build();

    String result = pineconeService.query(pineconeQueryReq, " ");
    
    // Carry the result and have a conversation with the chat service.
    // ......
}
```

### Delete data from vector database
```java
public void test_delete_vector_store() throws Exception {
    // Build parameters
    PineconeDelete pineconeDelete = PineconeDelete.builder()
                                    .deleteAll(true)
                                    .namespace("userId")
                                    .build();
    // Delete
    Boolean res = pineconeService.delete(pineconeDelete);
}
```



# Contribute to ai4j
You are welcome to provide suggestions, report issues, or contribute code to ai4j. You can contribute to ai4j in the following ways:

## Issue feedback
Please use the GitHub Issue page to report issues. Describe as specifically as possible how to reproduce your issue, including detailed information such as the operating system, Java version, and any relevant log traces.
## PR
1. Fork this repository and create your branch.
2. Write your code and test it.
3. Ensure that your code conforms to the existing style.
4. Write clear log information when submitting. For small changes, a single line of information is sufficient, but for larger changes, there should be a detailed description.
5. Complete the pull request form and ensure that changes are made on the `dev` branch and link to the issue that your PR addresses.

# Support
If you find this project helpful to you, please give it a star⭐。



================================================
FILE: README.md
================================================
<p align="center">
  <img src="https://capsule-render.vercel.app/api?type=waving&color=0:6A5ACD,100:2E86C1&height=180&section=header&text=ai4j&fontSize=46&fontColor=ffffff&animation=fadeIn&desc=Java%20AI%20Agentic%20SDK%20for%20JDK%208%2B&descAlignY=68" alt="ai4j banner" />
</p>

<p align="center">
  <a href="https://search.maven.org/artifact/io.github.lnyo-cly/ai4j">
    <img src="https://img.shields.io/maven-central/v/io.github.lnyo-cly/ai4j?color=2E86C1&label=Maven%20Central" alt="Maven Central" />
  </a>
  <a href="https://lnyo-cly.github.io/ai4j/">
    <img src="https://img.shields.io/badge/Docs-GitHub%20Pages-0A7EA4" alt="Docs" />
  </a>
  <a href="https://www.apache.org/licenses/LICENSE-2.0.txt">
    <img src="https://img.shields.io/badge/License-Apache%202.0-1F6FEB" alt="License" />
  </a>
  <img src="https://img.shields.io/badge/JDK-8%2B-2EA043" alt="JDK 8+" />
  <img src="https://img.shields.io/badge/Agentic-Enabled-6F42C1" alt="Agentic Enabled" />
  <img src="https://img.shields.io/badge/MCP-Supported-0F766E" alt="MCP Supported" />
  <img src="https://img.shields.io/badge/RAG-Built--in-B45309" alt="RAG Built-in" />
  <img src="https://img.shields.io/badge/CLI%20%2F%20TUI%20%2F%20ACP-Built--in-475569" alt="CLI TUI ACP Built-in" />
</p>

# ai4j
一款面向 JDK8+ 的 Java AI Agentic 开发套件,既提供统一的大模型调用与常用 AI 基座能力,也提供更完善的智能体式 Agent 开发能力。  
覆盖多平台模型接入、统一输入输出、Tool Call、MCP、RAG、统一 `VectorStore`、ChatMemory、Agent Runtime、Coding Agent、CLI / TUI / ACP、FlowGram 集成,以及 Dify / Coze / n8n 等已发布 AgentFlow 端点接入能力,帮助 Java 应用从基础模型接入扩展到更完整的 agentic 应用开发。

当前仓库已经演进为多模块 SDK,除核心 `ai4j` 外,还提供 `ai4j-agent`、`ai4j-coding`、`ai4j-cli`、`ai4j-spring-boot-starter`、`ai4j-flowgram-spring-boot-starter`、`ai4j-bom`。如果只需要基础大模型调用,优先引入 `ai4j`;如果需要 Agent、Coding Agent、CLI / ACP、Spring Boot 或 FlowGram 集成,再按模块引入对应能力。

## 适用场景与常见方案对比

| 方案 | Java 基线 | 应用形态 | 能力侧重点 |
| --- | --- | --- | --- |
| `ai4j` | `JDK8+` | 普通 Java / Spring | 统一大模型接入、Tool / MCP / RAG、Agent Runtime、Coding Agent、CLI / TUI / ACP |
| `Spring AI` | `Java 17+` | `Spring Boot 3.x` | Spring 原生 AI 集成、模型访问、Tool Calling、MCP、RAG |
| `Spring AI Alibaba` | `Java 17+` | `Spring Boot 3.x` | Spring 与阿里云 AI 生态整合 |
| `LangChain4j` | `Java 17+` | 普通 Java / Spring / Quarkus 等 | 通用 Java LLM / Agent / RAG 抽象、AI Services、多框架集成 |

## 支持的平台
+ OpenAi(包含与OpenAi请求格式相同/兼容的平台)
+ Jina(Rerank / Jina-compatible Rerank)
+ Zhipu(智谱)
+ DeepSeek(深度求索)
+ Moonshot(月之暗面)
+ Hunyuan(腾讯混元)
+ Lingyi(零一万物)
+ Ollama
+ MiniMax
+ Baichuan

## 支持的服务
+ Chat Completions(流式与非流式)
+ Responses
+ Embedding
+ Rerank
+ Audio
+ Image
+ Realtime

## 已适配的 AgentFlow / 工作流平台
+ Dify(Chat / Workflow)
+ Coze(Chat / Workflow)
+ n8n(Webhook Workflow)

## 特性
+ 支持MCP服务,内置MCP网关,支持建立动态MCP数据源。
+ 支持Spring以及普通Java应用、支持Java 8以上的应用
+ 多平台、多服务
+ 提供 `AgentFlow` 能力,可直接接入 Dify、Coze、n8n 等已发布 Agent / Workflow 端点
+ 提供 `ai4j-agent` 通用 Agent 运行时,支持 ReAct、subagent、agent teams、memory、trace 与 tool loop
+ 内置 Coding Agent CLI / TUI,支持本地代码仓交互式会话、provider profile、workspace model override、session/process 管理
+ 提供 `ai4j-coding` Coding Agent 运行时,支持 workspace tools、outer loop、checkpoint compaction、subagent 与 team 协作
+ 提供 `ai4j-flowgram-spring-boot-starter`,便于在 Spring Boot 中接入 FlowGram 工作流与 trace
+ 提供 `ai4j-bom`,便于多模块项目统一版本管理
+ 统一的输入输出
+ 统一的错误处理
+ 支持SPI机制,可自定义Dispatcher和ConnectPool
+ 支持服务增强,例如增加websearch服务
+ 支持流式输出。支持函数调用参数流式输出.
+ 简洁的多模态调用方式,例如vision识图
+ 轻松使用Tool Calls
+ 支持多个函数同时调用(智谱不支持)
+ 支持stream_options,流式输出直接获取统计token usage
+ 内置 `ChatMemory`,支持基础多轮会话上下文维护,可同时适配 Chat / Responses
+ 支持RAG,内置统一 `VectorStore` 抽象,当前支持: Pinecone、Qdrant、pgvector、Milvus
+ 内置 `IngestionPipeline`,统一串联 `DocumentLoader -> Chunker -> MetadataEnricher -> Embedding -> VectorStore.upsert`
+ 内置 `DenseRetriever`、`Bm25Retriever`、`HybridRetriever`,可按语义检索、关键词检索、混合检索方式组合知识库召回
+ `HybridRetriever` 支持 `RrfFusionStrategy`、`RsfFusionStrategy`、`DbsfFusionStrategy`,默认使用 RRF;融合排序与 `Reranker` 语义精排解耦
+ 支持统一 `IRerankService`,当前可接 Jina / Jina-compatible、Ollama、Doubao(方舟知识库重排);可通过 `ModelReranker` 无缝接入 RAG 精排
+ RAG 运行时可直接拿到 `rank/retrieverSource/retrievalScore/fusionScore/rerankScore/scoreDetails/trace`,并可通过 `RagEvaluator` 计算 `Precision@K/Recall@K/F1@K/MRR/NDCG`
+ 使用Tika读取文件
+ Token统计`TikTokensUtil.java`

## 官方文档站
+ 在线文档站:`https://lnyo-cly.github.io/ai4j/`
+ 文档站源码位于 `docs-site/`
+ 适合直接使用者的入口:`docs-site/docs/coding-agent/`
+ 适合 SDK 接入的入口:`docs-site/docs/getting-started/` 与 `docs-site/docs/ai-basics/`
+ 适合协议与扩展集成的入口:`docs-site/docs/mcp/`、`docs-site/docs/agent/`

推荐阅读顺序:

+ `docs-site/docs/intro.md`
+ `docs-site/docs/getting-started/installation.md`
+ `docs-site/docs/coding-agent/overview.md`
+ `docs-site/docs/ai-basics/overview.md`
+ `docs-site/docs/mcp/overview.md`

基础会话上下文新增入口:

+ `docs-site/docs/ai-basics/chat/chat-memory.md`
+ `docs-site/docs/ai-basics/services/rerank.md`
+ `docs-site/docs/ai-basics/rag/ingestion-pipeline.md`

本地运行文档站:

```powershell
cd .\docs-site
npm install
npm run start
```

```powershell
cd .\docs-site
npm run build
```

## 更新日志
+ [2026-03-28] 修复 Coding Agent ACP 流式场景下纯空白 chunk 被 runtime 过滤的问题;ACP 保持透传原始 delta,不做 chunk 聚合;补充 CLI/文档中的流式语义说明
+ [2026-03-26] 新增 Coding Agent CLI / TUI 文档与能力说明,覆盖交互式会话、provider profile、workspace model override、命令参考与配置样例
+ [2025-08-19] 修复传递有验证参数的sse-url时,key丢失问题
+ [2025-08-08] OpenAi: max_tokens字段现已废弃,推荐使用max_completion_tokens(GPT-5已经不支持max_tokens字段)
+ [2025-08-08] 支持MCP协议,支持STDIO,SSE,Streamable HTTP; 支持MCP Server与MCP Client; 支持MCP网关; 支持自定义MCP数据源; 支持MCP自动重连
+ [2025-06-23] 修复ollama的流式错误;修复ollama函数调用的错误;修复moonshot请求时错误;修复ollama embedding错误;修复思考无内容;修复日志冲突;新增自定义异常方法。
+ [2025-02-28] 新增对Ollama平台的embedding接口的支持。
+ [2025-02-17] 新增对DeepSeek平台推理模型的适配。
+ [2025-02-12] 为Ollama平台添加Authorization
+ [2025-02-11] 实现自定义的Jackson序列化,解决OpenAi已经无法通过Json String来直接实现多模态接口的问题。
+ [2024-12-12] 使用装饰器模式增强Chat服务,支持SearXNG网络搜索增强,无需模型支持内置搜索以及function_call。
+ [2024-10-17] 支持SPI机制,可自定义Dispatcher和ConnectPool。新增百川Baichuan平台Chat接口支持。
+ [2024-10-16] 增加MiniMax平台Chat接口对接
+ [2024-10-15] 增加realtime服务
+ [2024-10-12] 修复早期遗忘的小bug; 修复错误拦截器导致的音频字节流异常错误问题; 增加OpenAi Audio服务。
+ [2024-10-10] 增强对SSE输出的获取,新加入`currData`属性,记录当前消息的整个对象。而原先的`currStr`为当前消息的content内容,保留不变。
+ [2024-09-26] 修复有关Pinecone向量数据库的一些问题。发布0.6.3版本
+ [2024-09-20] 增加对Ollama平台的支持,并修复一些bug。发布0.6.2版本
+ [2024-09-19] 增加错误处理链,统一处理为openai错误类型; 修复部分情况下URL拼接问题,修复拦截器中response重复调用而导致的关闭问题。发布0.5.3版本
+ [2024-09-12] 修复上个问题OpenAi参数导致错误的遗漏,发布0.5.2版本
+ [2024-09-12] 修复SpringBoot 2.6以下导致OkHttp变为3.14版本的报错问题;修复OpenAi参数`parallel_tool_calls`在tools为null时的异常问题。发布0.5.1版本。
+ [2024-09-09] 新增零一万物大模型支持、发布0.5.0版本。
+ [2024-09-02] 新增腾讯混元Hunyuan平台支持(注意:所需apiKey 属于SecretId与SecretKey的拼接,格式为 {SecretId}.{SecretKey}),发布0.4.0版本。
+ [2024-08-30] 新增对Moonshot(Kimi)平台的支持,增加`OkHttpUtil.java`实现忽略SSL证书的校验。
+ [2024-08-29] 新增对DeepSeek平台的支持、新增stream_options可以直接统计usage、新增错误拦截器`ErrorInterceptor.java`、发布0.3.0版本。
+ [2024-08-29] 修改SseListener以兼容智谱函数调用。
+ [2024-08-28] 添加token统计、添加智谱AI的Chat服务、优化函数调用可以支持多轮多函数。
+ [2024-08-17] 增强SseListener监听器功能。发布0.2.0版本。

## 教程文档
+ [快速接入SpringBoot、接入流式与非流式以及函数调用](http://t.csdnimg.cn/iuIAW)
+ [Java快速接入qwen2.5、llama3.1等Ollama平台开源大模型](https://blog.csdn.net/qq_35650513/article/details/142408092?spm=1001.2014.3001.5501)
+ [Java搭建法律AI助手,快速实现RAG应用](https://blog.csdn.net/qq_35650513/article/details/142568177?fromshare=blogdetail&sharetype=blogdetail&sharerId=142568177&sharerefer=PC&sharesource=qq_35650513&sharefrom=from_link)
+ [大模型不支持联网搜索?为Deepseek、Qwen、llama等本地模型添加网络搜索](https://blog.csdn.net/qq_35650513/article/details/144572824)
+ [java快速接入mcp以及结合mysql动态管理](https://blog.csdn.net/qq_35650513/article/details/150532784?fromshare=blogdetail&sharetype=blogdetail&sharerId=150532784&sharerefer=PC&sharesource=qq_35650513&sharefrom=from_link)

## Coding Agent CLI / TUI

AI4J 目前已经内置 `ai4j-cli`,可以直接作为本地 coding agent 使用,支持:

+ one-shot 与持续会话
+ CLI / TUI 两种交互模式
+ provider profile 持久化
+ workspace 级 model override
+ subagent 与 agent teams 协作
+ session 持久化、resume、fork、history、tree、events、replay
+ team board、team messages、team resume 等协作观测能力
+ process 管理与日志查看

### 安装

```bash
curl -fsSL https://lnyo-cly.github.io/ai4j/install.sh | sh
```

```powershell
irm https://lnyo-cly.github.io/ai4j/install.ps1 | iex
```

安装脚本会从 Maven Central 下载 `ai4j-cli` 并生成 `ai4j` 命令,前提是本机已经安装 Java 8+。

### one-shot 示例

```powershell
ai4j code `
  --provider openai `
  --protocol responses `
  --model gpt-5-mini `
  --prompt "Read README and summarize the project structure"
```

### 交互式 CLI 示例

```powershell
ai4j code `
  --provider zhipu `
  --protocol chat `
  --model glm-4.7 `
  --base-url https://open.bigmodel.cn/api/coding/paas/v4 `
  --workspace .
```

### TUI 示例

```powershell
ai4j tui `
  --provider zhipu `
  --protocol chat `
  --model glm-4.7 `
  --base-url https://open.bigmodel.cn/api/coding/paas/v4 `
  --workspace .
```

### ACP 示例

```powershell
ai4j acp `
  --provider openai `
  --protocol responses `
  --model gpt-5-mini `
  --workspace .
```

### 源码构建(可选)

```powershell
mvn -pl ai4j-cli -am -DskipTests package
```

产物示例:

```text
ai4j-cli/target/ai4j-cli-<version>-jar-with-dependencies.jar
```

如果你需要直接运行本地构建产物:

```powershell
java -jar .\ai4j-cli\target\ai4j-cli-<version>-jar-with-dependencies.jar code --help
```

### 当前协议规则

当前 CLI 对用户只暴露两种协议:

+ `chat`
+ `responses`

如果省略 `--protocol`,会按 provider/baseUrl 在本地推导默认值:

+ `openai` + 官方 OpenAI host -> `responses`
+ `openai` + 自定义兼容 `baseUrl` -> `chat`
+ `doubao` / `dashscope` -> `responses`
+ 其他 provider -> `chat`

注意:

+ 不再对用户暴露 `auto`
+ 旧配置中的 `auto` 会在读取时自动归一化为显式协议

### provider profile 配置位置

+ 全局配置:`~/.ai4j/providers.json`
+ 工作区配置:`<workspace>/.ai4j/workspace.json`

推荐工作流:

+ 全局保存长期可复用 profile
+ workspace 只引用当前 activeProfile
+ 临时切模型时使用 workspace 的 `modelOverride`

`workspace.json` 也可以显式挂载额外 skill 目录:

```json
{
  "activeProfile": "openai-main",
  "modelOverride": "gpt-5-mini",
  "enabledMcpServers": ["fetch"],
  "skillDirectories": [
    ".ai4j/skills",
    "C:/skills/team",
    "../shared-skills"
  ]
}
```

skill 发现规则:

+ 默认扫描 `<workspace>/.ai4j/skills`
+ 默认扫描 `~/.ai4j/skills`
+ `skillDirectories` 中的相对路径按 workspace 根目录解析
+ 进入 CLI 后可用 `/skills` 查看当前发现到的 skill
+ 可用 `/skills <name>` 查看某个 skill 的路径、来源、描述和扫描 roots,不打印 `SKILL.md` 正文

### `/stream`、`Esc` 与状态提示

当前 `/stream` 的语义是“当前 CLI 会话里的模型请求是否启用 `stream`”,不是单纯的 transcript 渲染开关:

+ 作用域是当前 CLI 会话
+ `/stream on|off` 会切换请求级 `stream=true|false`,并立即重建当前 session runtime
+ `on` 时 provider 响应按增量到达,assistant 文本也按增量呈现
+ `off` 时等待完整响应后再输出整理后的完成块
+ 流式 event 粒度由上游 provider/SSE 决定,不保证“一个 event = 一个 token”
+ 如果通过 ACP/IDE 接入,宿主应按收到的 chunk 顺序渲染,并保留换行与空白

当前交互壳层里:

+ `Esc` 在活跃 turn 中断当前任务;空闲时关闭 palette 或清空输入
+ 状态栏会显示 `Thinking`、`Connecting`、`Responding`、`Working`、`Retrying`
+ 一段时间没有新进展会升级为 `Waiting`
+ 更久没有新进展会显示 `Stalled`,并提示 `press Esc to interrupt`

### 常用命令

+ `/providers`
+ `/provider`
+ `/provider use <name>`
+ `/provider save <name>`
+ `/provider add <name> --provider <name> [--protocol <chat|responses>] [--model <name>] [--base-url <url>] [--api-key <key>]`
+ `/provider edit <name> [--provider <name>] [--protocol <chat|responses>] [--model <name>|--clear-model] [--base-url <url>|--clear-base-url] [--api-key <key>|--clear-api-key]`
+ `/provider default <name|clear>`
+ `/provider remove <name>`
+ `/model`
+ `/model <name>`
+ `/model reset`
+ `/skills`
+ `/skills <name>`
+ `/stream [on|off]`
+ `/processes`
+ `/process status|follow|logs|write|stop ...`
+ `/resume <id>` / `/load <id>` / `/fork ...`

### 文档入口

+ [Coding Agent 总览](docs-site/docs/coding-agent/overview.md)
+ [Coding Agent 快速开始](docs-site/docs/coding-agent/quickstart.md)
+ [CLI / TUI 使用指南](docs-site/docs/coding-agent/cli-and-tui.md)
+ [会话、流式与进程](docs-site/docs/coding-agent/session-runtime.md)
+ [配置体系](docs-site/docs/coding-agent/configuration.md)
+ [Tools 与审批机制](docs-site/docs/coding-agent/tools-and-approvals.md)
+ [Skills 使用与组织](docs-site/docs/coding-agent/skills.md)
+ [MCP 对接](docs-site/docs/coding-agent/mcp-integration.md)
+ [ACP 集成](docs-site/docs/coding-agent/acp-integration.md)
+ [TUI 定制与主题](docs-site/docs/coding-agent/tui-customization.md)
+ [命令参考](docs-site/docs/coding-agent/command-reference.md)

## 其它支持
+ [[低价中转平台] 低价ApiKey—限时特惠 ](https://api.trovebox.online/)
+ [[在线平台] 每日白嫖额度-所有模型均可使用 ](https://chat.trovebox.online/)

# 快速开始
## 导入
### 模块选型
+ 只需要基础 LLM / Tool Call / MCP / RAG 能力:引入 `ai4j`
+ 需要通用 Agent 运行时:引入 `ai4j-agent`
+ 需要 Coding Agent、workspace tools、outer loop:引入 `ai4j-coding`
+ 需要本地 CLI / TUI / ACP 宿主:引入 `ai4j-cli`
+ 需要 Spring Boot 自动配置:引入 `ai4j-spring-boot-starter`
+ 需要 FlowGram 工作流集成:引入 `ai4j-flowgram-spring-boot-starter`
+ 同时引入多个模块:建议额外引入 `ai4j-bom`

### Gradle
```groovy
implementation platform("io.github.lnyo-cly:ai4j-bom:${project.version}")
implementation "io.github.lnyo-cly:ai4j"
implementation "io.github.lnyo-cly:ai4j-agent"
```

```groovy
implementation group: 'io.github.lnyo-cly', name: 'ai4j', version: '${project.version}'
```

```groovy
implementation group: 'io.github.lnyo-cly', name: 'ai4j-spring-boot-starter', version: '${project.version}'
```


### Maven
```xml
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.github.lnyo-cly</groupId>
            <artifactId>ai4j-bom</artifactId>
            <version>${project.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
```

```xml
<!-- 多模块项目推荐 -->
<dependency>
    <groupId>io.github.lnyo-cly</groupId>
    <artifactId>ai4j-agent</artifactId>
</dependency>

<dependency>
    <groupId>io.github.lnyo-cly</groupId>
    <artifactId>ai4j-coding</artifactId>
</dependency>
```

```xml
<!-- 非Spring应用 -->
<dependency>
    <groupId>io.github.lnyo-cly</groupId>
    <artifactId>ai4j</artifactId>
    <version>${project.version}</version>
</dependency>

```
```xml
<!-- Spring应用 -->
<dependency>
    <groupId>io.github.lnyo-cly</groupId>
    <artifactId>ai4j-spring-boot-starter</artifactId>
    <version>${project.version}</version>
</dependency>
```

## 获取AI服务实例

### 非Spring获取
```java
    public void test_init(){
        OpenAiConfig openAiConfig = new OpenAiConfig();

        Configuration configuration = new Configuration();
        configuration.setOpenAiConfig(openAiConfig);

        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);

        OkHttpClient okHttpClient = new OkHttpClient
                .Builder()
                .addInterceptor(httpLoggingInterceptor)
                .addInterceptor(new ErrorInterceptor())
                .connectTimeout(300, TimeUnit.SECONDS)
                .writeTimeout(300, TimeUnit.SECONDS)
                .readTimeout(300, TimeUnit.SECONDS)
                .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1",10809)))
                .build();
        configuration.setOkHttpClient(okHttpClient);

        AiService aiService = new AiService(configuration);

        embeddingService = aiService.getEmbeddingService(PlatformType.OPENAI);
        chatService = aiService.getChatService(PlatformType.getPlatform("OPENAI"));

    }
```
### Spring获取
```yml
# 国内访问默认需要代理
ai:
  openai:
    api-key: "api-key"
  okhttp:
    proxy-port: 10809
    proxy-url: "127.0.0.1"
  zhipu:
    api-key: "xxx"
  #other...
```

```java
// 注入Ai服务
@Autowired
private AiService aiService;

// 获取需要的服务实例
IChatService chatService = aiService.getChatService(PlatformType.OPENAI);
IEmbeddingService embeddingService = aiService.getEmbeddingService(PlatformType.OPENAI);
// ......
```

## Chat服务

### 同步请求调用
```java

public void test_chat() throws Exception {
    // 获取chat服务实例
    IChatService chatService = aiService.getChatService(PlatformType.OPENAI);

    // 构建请求参数
    ChatCompletion chatCompletion = ChatCompletion.builder()
            .model("gpt-4o-mini")
            .message(ChatMessage.withUser("鲁迅为什么打周树人"))
            .build();

    // 发送对话请求
    ChatCompletionResponse response = chatService.chatCompletion(chatCompletion);

    System.out.println(response);
}

```

### 流式调用
```java
public void test_chat_stream() throws Exception {
    // 获取chat服务实例
    IChatService chatService = aiService.getChatService(PlatformType.OPENAI);

    // 构造请求参数
    ChatCompletion chatCompletion = ChatCompletion.builder()
            .model("gpt-4o-mini")
            .message(ChatMessage.withUser("查询北京明天的天气"))
            .functions("queryWeather")
            .build();


    // 构造监听器
    SseListener sseListener = new SseListener() {
        @Override
        protected void send() {
            System.out.println(this.getCurrStr());
        }
    };
    // 显示函数参数,默认不显示
    sseListener.setShowToolArgs(true);

    // 发送SSE请求
    chatService.chatCompletionStream(chatCompletion, sseListener);

    System.out.println(sseListener.getOutput());

}
```

### 图片识别

```java
public void test_chat_image() throws Exception {
    // 获取chat服务实例
    IChatService chatService = aiService.getChatService(PlatformType.OPENAI);

    // 构建请求参数
    ChatCompletion chatCompletion = ChatCompletion.builder()
            .model("gpt-4o-mini")
            .message(ChatMessage.withUser("图片中有什么东西", "https://cn.bing.com/images/search?view=detailV2&ccid=r0OnuYkv&id=9A07DE578F6ED50DB59DFEA5C675AC71845A6FC9&thid=OIP.r0OnuYkvsbqBrYk3kUT53AHaKX&mediaurl=https%3a%2f%2fimg.zcool.cn%2fcommunity%2f0104c15cd45b49a80121416816f1ec.jpg%401280w_1l_2o_100sh.jpg&exph=1792&expw=1280&q=%e5%b0%8f%e7%8c%ab%e5%9b%be%e7%89%87&simid=607987191780608963&FORM=IRPRST&ck=12127C1696CF374CB9D0F09AE99AFE69&selectedIndex=2&itb=0&qpvt=%e5%b0%8f%e7%8c%ab%e5%9b%be%e7%89%87"))
            .build();

    // 发送对话请求
    ChatCompletionResponse response = chatService.chatCompletion(chatCompletion);

    System.out.println(response);
}
```

### 函数调用

```java
public void test_chat_tool_call() throws Exception {
    // 获取chat服务实例
    IChatService chatService = aiService.getChatService(PlatformType.OPENAI);

    // 构建请求参数
    ChatCompletion chatCompletion = ChatCompletion.builder()
            .model("gpt-4o-mini")
            .message(ChatMessage.withUser("今天北京天气怎么样"))
            .functions("queryWeather")
            .build();

    // 发送对话请求
    ChatCompletionResponse response = chatService.chatCompletion(chatCompletion);

    System.out.println(response);
}
```

### 内置 ChatMemory

如果你只是做基础多轮对话,不想自己每轮维护完整上下文,可以直接使用 `ChatMemory`:

```java
IChatService chatService = aiService.getChatService(PlatformType.OPENAI);

ChatMemory memory = new InMemoryChatMemory(new MessageWindowChatMemoryPolicy(12));
memory.addSystem("你是一个简洁的 Java 助手");
memory.addUser("请用三点介绍 AI4J");

ChatCompletion request = ChatCompletion.builder()
        .model("gpt-4o-mini")
        .messages(memory.toChatMessages())
        .build();

ChatCompletionResponse response = chatService.chatCompletion(request);
String answer = response.getChoices().get(0).getMessage().getContent().getText();

memory.addAssistant(answer);
```

同一份 `memory` 也可以直接给 `Responses`:

```java
IResponsesService responsesService = aiService.getResponsesService(PlatformType.DOUBAO);

ResponseRequest request = ResponseRequest.builder()
        .model("doubao-seed-1-8-251228")
        .input(memory.toResponsesInput())
        .build();
```
#### 定义函数
```java
@FunctionCall(name = "queryWeather", description = "查询目标地点的天气预报")
public class QueryWeatherFunction implements Function<QueryWeatherFunction.Request, String> {

    @Data
    @FunctionRequest
    public static class Request{
        @FunctionParameter(description = "需要查询天气的目标位置, 可以是城市中文名、城市拼音/英文名、省市名称组合、IP 地址、经纬度")
        private String location;
        @FunctionParameter(description = "需要查询未来天气的天数, 最多15日")
        private int days = 15;
        @FunctionParameter(description = "预报的天气类型,daily表示预报多天天气、hourly表示预测当天24天气、now为当前天气实况")
        private Type type;
    }

    public enum Type{
        daily,
        hourly,
        now
    }

    @Override
    public String apply(Request request) {
        final String key = "";

        String url = String.format("https://api.seniverse.com/v3/weather/%s.json?key=%s&location=%s&days=%d",
                request.type.name(),
                key,
                request.location,
                request.days);


        OkHttpClient client = new OkHttpClient();

        okhttp3.Request http = new okhttp3.Request.Builder()
                .url(url)
                .get()
                .build();

        try (Response response = client.newCall(http).execute()) {
            if (response.isSuccessful()) {
                // 解析响应体
                return response.body() != null ? response.body().string() : "";
            } else {
                return "获取天气失败 当前天气未知";
            }
        } catch (Exception e) {
            // 处理异常
            e.printStackTrace();
            return "获取天气失败 当前天气未知";
        }
    }

}
```

## Embedding服务

```java
public void test_embed() throws Exception {
    // 获取embedding服务实例
    IEmbeddingService embeddingService = aiService.getEmbeddingService(PlatformType.OPENAI);

    // 构建请求参数
    Embedding embeddingReq = Embedding.builder().input("1+1").build();

    // 发送embedding请求
    EmbeddingResponse embeddingResp = embeddingService.embedding(embeddingReq);

    System.out.println(embeddingResp);
}
```

## Rerank服务

### 直接调用统一重排服务

```java
IRerankService rerankService = aiService.getRerankService(PlatformType.JINA);

RerankRequest request = RerankRequest.builder()
        .model("jina-reranker-v2-base-multilingual")
        .query("哪段最适合回答 Java 8 为什么仍然常见")
        .documents(Arrays.asList(
                RerankDocument.builder().id("doc-1").text("Java 8 仍是很多传统系统的默认运行时").build(),
                RerankDocument.builder().id("doc-2").text("AI4J 提供统一 Chat、Responses 和 RAG 接口").build(),
                RerankDocument.builder().id("doc-3").text("历史中间件和升级成本让很多企业延后 JDK 升级").build()
        ))
        .topN(2)
        .build();

RerankResponse response = rerankService.rerank(request);
System.out.println(response.getResults());
```

### 作为 RAG 精排器接入

```java
Reranker reranker = aiService.getModelReranker(
        PlatformType.JINA,
        "jina-reranker-v2-base-multilingual",
        5,
        "优先保留制度原文、版本说明和编号明确的片段"
);
```

## RAG
### 推荐:使用统一 IngestionPipeline 入库

```java
VectorStore vectorStore = aiService.getQdrantVectorStore();

IngestionPipeline ingestionPipeline = aiService.getIngestionPipeline(
        PlatformType.OPENAI,
        vectorStore
);

IngestionResult ingestResult = ingestionPipeline.ingest(IngestionRequest.builder()
        .dataset("kb_docs")
        .embeddingModel("text-embedding-3-small")
        .document(RagDocument.builder()
                .sourceName("员工手册")
                .sourcePath("/docs/employee-handbook.md")
                .tenant("acme")
                .biz("hr")
                .version("2026.03")
                .build())
        .source(IngestionSource.text("第一章 假期政策。第二章 报销政策。"))
        .build());

System.out.println(ingestResult.getUpsertedCount());
```

如果你已经走 Pinecone,也可以直接:

```java
IngestionPipeline ingestionPipeline = aiService.getPineconeIngestionPipeline(PlatformType.OPENAI);
```

推荐主线是:

1. `IngestionPipeline` 负责文档入库
2. `VectorStore` 负责底层向量存储
3. `DenseRetriever / HybridRetriever / ModelReranker / RagService` 负责查询阶段

完整说明见:

+ `docs-site/docs/ai-basics/rag/ingestion-pipeline.md`
+ `docs-site/docs/ai-basics/rag/overview.md`

### 配置向量数据库
```yml
ai:
  vector:
    pinecone:
      host: ""
      key: ""
```
### 推荐:Pinecone 也走统一 `VectorStore + IngestionPipeline`

```java
VectorStore vectorStore = aiService.getPineconeVectorStore();

IngestionPipeline ingestionPipeline = aiService.getPineconeIngestionPipeline(PlatformType.OPENAI);

IngestionResult ingestResult = ingestionPipeline.ingest(IngestionRequest.builder()
        .dataset("tenant_a_hr_v202603")
        .embeddingModel("text-embedding-3-small")
        .document(RagDocument.builder()
                .sourceName("员工手册")
                .sourcePath("/docs/employee-handbook.pdf")
                .tenant("tenant_a")
                .biz("hr")
                .version("2026.03")
                .build())
        .source(IngestionSource.file(new File("D:/data/employee-handbook.pdf")))
        .build());

System.out.println("upserted=" + ingestResult.getUpsertedCount());
```

### 查询阶段:直接走统一 `RagService`

```java
RagService ragService = aiService.getRagService(
        PlatformType.OPENAI,
        vectorStore
);

RagQuery ragQuery = RagQuery.builder()
        .query("年假如何计算")
        .dataset("tenant_a_hr_v202603")
        .embeddingModel("text-embedding-3-small")
        .topK(5)
        .build();

RagResult ragResult = ragService.search(ragQuery);

System.out.println(ragResult.getContext());
System.out.println(ragResult.getCitations());
```

### 如果需要更高精度,再接 Rerank

```java
Reranker reranker = aiService.getModelReranker(
        PlatformType.JINA,
        "jina-reranker-v2-base-multilingual",
        5,
        "优先制度原文、章节标题和编号明确的片段"
);

RagService ragService = new DefaultRagService(
        new DenseRetriever(
                aiService.getEmbeddingService(PlatformType.OPENAI),
                vectorStore
        ),
        reranker,
        new DefaultRagContextAssembler()
);
```

### 什么时候还需要直接用已废弃的 `PineconeService`(Deprecated)

`PineconeService` 目前在文档层已视为 Deprecated。只有在你明确需要 Pinecone 特有的底层控制时,才建议继续直接用:

+ namespace 级底层操作
+ 兼容旧项目里已经写死的 `PineconeQuery / PineconeDelete`
+ 你就是在做 Pinecone 专用封装,而不是面向统一 RAG 抽象开发

## 内置联网

### SearXNG

#### 配置
```java
// 非spring应用
SearXNGConfig searXNGConfig = new SearXNGConfig();
searXNGConfig.setUrl("http://127.0.0.1:8080/search");

Configuration configuration = new Configuration();
configuration.setSearXNGConfig(searXNGConfig);
```

```YML
# spring应用
ai:
  websearch:
    searxng:
      url: http://127.0.0.1:8080/search

```

#### 使用

```java

// ...

webEnhance = aiService.webSearchEnhance(chatService);

// ...


@Test
public void test_chatCompletions_common_websearch_enhance() throws Exception {
    ChatCompletion chatCompletion = ChatCompletion.builder()
            .model("qwen2.5:7b")
            .message(ChatMessage.withUser("鸡你太美是什么梗"))
            .build();

    System.out.println("请求参数");
    System.out.println(chatCompletion);

    ChatCompletionResponse chatCompletionResponse = webEnhance.chatCompletion(chatCompletion);

    System.out.println("请求成功");
    System.out.println(chatCompletionResponse);

}
```


# 为AI4J提供贡献
欢迎您对AI4J提出建议、报告问题或贡献代码。您可以按照以下的方式为AI4J提供贡献: 

## 问题反馈
请使用GitHub Issue页面报告问题。尽可能具体地说明如何重现您的问题,包括操作系统、Java版本和任何相关日志跟踪等详细信息。

## PR
1. Fork 本仓库并创建您的分支(建议命名:feature/功能名、fix/问题名 或 docs/文档优化)。
2. 编写代码或修改内容(如更新文档),并完成测试(确保功能正常或文档无误)。
3. 确保您的代码符合现有的样式。
4. 提交时编写清晰的日志信息。对于小的改动,单行信息就可以了,但较大的改动应该有详细的描述。
5. 完成拉取请求表单,确保在`dev`分支进行改动,链接到您的 PR 解决的问题。

# 支持
如果您觉得这个项目对您有帮助,请点一个star⭐。

# Buy Me a Coffee
您的支持是我更新的最大的动力。

![新图片](https://cdn.jsdelivr.net/gh/lnyo-cly/blogImg/pics/新图片.jpg)

# 贡献者

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->

<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

<a href="https://github.com/LnYo-Cly/ai4j/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=LnYo-Cly/ai4j" />
</a>


# ⭐️ Star History
<a href="https://star-history.com/#LnYo-Cly/ai4j&Date">
 <picture>
   <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=LnYo-Cly/ai4j&type=Date&theme=dark" />
   <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=LnYo-Cly/ai4j&type=Date" />
   <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=LnYo-Cly/ai4j&type=Date" />
 </picture>
</a>



================================================
FILE: ai4j/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>io.github.lnyo-cly</groupId>
    <artifactId>ai4j</artifactId>
    <packaging>jar</packaging>
    <version>2.3.0</version>

    <name>ai4j</name>
    <description>ai4j 核心 Java SDK,提供统一大模型接入、Tool Call、RAG 与 MCP 能力。 Core Java SDK for unified LLM access, tool calling, RAG, and MCP integration.</description>


    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <skipTests>true</skipTests>
        <graalvm.version>20.3.4</graalvm.version>
        <graalsdk.version>${graalvm.version}</graalsdk.version>
        <nashorn.version>15.6</nashorn.version>
    </properties>
    <licenses>
        <license>
            <name>The Apache License, Version 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
        </license>
    </licenses>

    <issueManagement>
        <system>GitHub</system>
        <url>https://github.com/LnYo-Cly/ai4j/issues</url>
    </issueManagement>

    <url>https://github.com/LnYo-Cly/ai4j</url>
    <developers>
        <developer>
            <id>LnYo-Cly</id>
            <name>LnYo-Cly</name>
            <email>lnyocly@gmail.com</email>
            <url>https://github.com/LnYo-Cly/ai4j</url>
            <timezone>+8</timezone>
        </developer>
    </developers>

    <scm>
        <!--项目访问url -->
        <url>https://github.com/LnYo-Cly/ai4j</url>
        <!--项目访问url.git结尾 -->
        <connection>scm:git:https://github.com/LnYo-Cly/ai4j.git</connection>
        <!--项目访问url.git结尾 -->
        <developerConnection>scm:git:https://github.com/LnYo-Cly/ai4j.git</developerConnection>
    </scm>

    <dependencies>
        <!-- 日志实现,例如 slf4j-simple -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.30</version>
        </dependency>
        <!-- Apache Tika core -->
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-core</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-parsers-standard-package</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>com.knuddels</groupId>
            <artifactId>jtokkit</artifactId>
            <version>1.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>

        <dependency>
            <groupId>org.reflections</groupId>
            <artifactId>reflections</artifactId>
            <version>0.10.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>2.2.224</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>mockwebserver</artifactId>
            <version>4.12.0</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.43</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.16.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.14.2</version>
        </dependency>

        <!-- okhttp -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.12.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp-sse -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp-sse</artifactId>
            <version>4.12.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/logging-interceptor -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>logging-interceptor</artifactId>
            <version>4.12.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>33.0.0-jre</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.4.0</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>5.8.38</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dashscope-sdk-java</artifactId>
            <scope>compile</scope>
            <version>2.19.0</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains</groupId>
            <artifactId>annotations</artifactId>
            <version>13.0</version>
        </dependency>

        <!-- GraalVM Polyglot SDK for CodeAct Python runtime -->
        <dependency>
            <groupId>org.graalvm.sdk</groupId>
            <artifactId>graal-sdk</artifactId>
            <version>${graalsdk.version}</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.name}-${project.version}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.12.4</version>
                <configuration>
                    <skipTests>${skipTests}</skipTests>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF8</encoding>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <parameters>true</parameters>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>1.18.30</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>

        </plugins>
    </build>



    <profiles>
        <profile>
            <id>nashorn-runtime</id>
            <activation>
                <jdk>[15,)</jdk>
            </activation>
            <dependencies>
                <dependency>
                    <groupId>org.openjdk.nashorn</groupId>
                    <artifactId>nashorn-core</artifactId>
                    <version>${nashorn.version}</version>
                    <scope>runtime</scope>
                </dependency>
            </dependencies>
        </profile>
        <profile>
            <id>graalpy-runtime</id>
            <activation>
                <jdk>[17,)</jdk>
            </activation>
            <properties>
                <graalsdk.version>24.1.2</graalsdk.version>
            </properties>
            <dependencies>
                <dependency>
                    <groupId>org.graalvm.python</groupId>
                    <artifactId>python-community</artifactId>
                    <version>${graalsdk.version}</version>
                    <type>pom</type>
                    <scope>runtime</scope>
                </dependency>
            </dependencies>
        </profile>

        <profile>
            <id>release</id>
            <build>
                <plugins>
                    <!-- source源码插件 -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-source-plugin</artifactId>
                        <version>3.3.1</version>
                        <executions>
                            <execution>
                                <id>attach-sources</id>
                                <goals>
                                    <goal>jar-no-fork</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>

                    <!-- Javadoc插件 -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-javadoc-plugin</artifactId>
                        <version>3.6.3</version>
                        <executions>
                            <execution>
                                <id>attach-javadocs</id>
                                <goals>
                                    <goal>jar</goal>
                                </goals>
                                <configuration>
                                    <doclint>none</doclint>
                                    <failOnError>false</failOnError>
                                    <tags>
                                        <tag>
                                            <name>Author</name>
                                            <placement>a</placement>
                                            <head>Author:</head>
                                        </tag>
                                        <tag>
                                            <name>Description</name>
                                            <placement>a</placement>
                                            <head>Description:</head>
                                        </tag>
                                        <tag>
                                            <name>Date</name>
                                            <placement>a</placement>
                                            <head>Date:</head>
                                        </tag>
                                    </tags>
                                </configuration>
                            </execution>

                        </executions>
                    </plugin>

                    <!-- GPG插件 -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-gpg-plugin</artifactId>
                        <version>1.6</version>
                        <configuration>
                            <executable>D:\Develop\DevelopEnv\GnuPG\bin\gpg.exe</executable>
                            <keyname>cly</keyname>
                        </configuration>
                        <executions>
                            <execution>
                                <id>sign-artifacts</id>
                                <phase>verify</phase>
                                <goals>
                                    <goal>sign</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>

                    <!--   central发布插件    -->
                    <plugin>
                        <groupId>org.sonatype.central</groupId>
                        <artifactId>central-publishing-maven-plugin</artifactId>
                        <version>0.4.0</version>
                        <extensions>true</extensions>
                        <configuration>
                            <publishingServerId>LnYo-Cly</publishingServerId>
                            <tokenAuth>true</tokenAuth>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

</project>




================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/AgentFlow.java
================================================
package io.github.lnyocly.ai4j.agentflow;

import io.github.lnyocly.ai4j.agentflow.chat.AgentFlowChatService;
import io.github.lnyocly.ai4j.agentflow.chat.CozeAgentFlowChatService;
import io.github.lnyocly.ai4j.agentflow.chat.DifyAgentFlowChatService;
import io.github.lnyocly.ai4j.agentflow.workflow.AgentFlowWorkflowService;
import io.github.lnyocly.ai4j.agentflow.workflow.CozeAgentFlowWorkflowService;
import io.github.lnyocly.ai4j.agentflow.workflow.DifyAgentFlowWorkflowService;
import io.github.lnyocly.ai4j.agentflow.workflow.N8nAgentFlowWorkflowService;
import io.github.lnyocly.ai4j.service.Configuration;

public class AgentFlow {

    private final Configuration configuration;
    private final AgentFlowConfig config;

    public AgentFlow(Configuration configuration, AgentFlowConfig config) {
        if (configuration == null) {
            throw new IllegalArgumentException("configuration is required");
        }
        if (config == null) {
            throw new IllegalArgumentException("agentFlowConfig is required");
        }
        this.configuration = configuration;
        this.config = config;
    }

    public Configuration getConfiguration() {
        return configuration;
    }

    public AgentFlowConfig getConfig() {
        return config;
    }

    public AgentFlowChatService chat() {
        if (config.getType() == AgentFlowType.DIFY) {
            return new DifyAgentFlowChatService(configuration, config);
        }
        if (config.getType() == AgentFlowType.COZE) {
            return new CozeAgentFlowChatService(configuration, config);
        }
        throw new IllegalArgumentException("Chat is not supported for agent flow type: " + config.getType());
    }

    public AgentFlowWorkflowService workflow() {
        if (config.getType() == AgentFlowType.DIFY) {
            return new DifyAgentFlowWorkflowService(configuration, config);
        }
        if (config.getType() == AgentFlowType.COZE) {
            return new CozeAgentFlowWorkflowService(configuration, config);
        }
        if (config.getType() == AgentFlowType.N8N) {
            return new N8nAgentFlowWorkflowService(configuration, config);
        }
        throw new IllegalArgumentException("Workflow is not supported for agent flow type: " + config.getType());
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/AgentFlowConfig.java
================================================
package io.github.lnyocly.ai4j.agentflow;

import io.github.lnyocly.ai4j.agentflow.trace.AgentFlowTraceListener;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;

import java.util.Collections;
import java.util.List;
import java.util.Map;

@Data
@Builder(toBuilder = true)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AgentFlowConfig {

    @NonNull
    private AgentFlowType type;

    private String baseUrl;

    private String webhookUrl;

    private String apiKey;

    private String botId;

    private String workflowId;

    private String appId;

    private String userId;

    private String conversationId;

    @Builder.Default
    private Long pollIntervalMillis = 1_000L;

    @Builder.Default
    private Long pollTimeoutMillis = 60_000L;

    @Builder.Default
    private Map<String, String> headers = Collections.emptyMap();

    @Builder.Default
    private List<AgentFlowTraceListener> traceListeners = Collections.emptyList();
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/AgentFlowException.java
================================================
package io.github.lnyocly.ai4j.agentflow;

public class AgentFlowException extends RuntimeException {

    public AgentFlowException(String message) {
        super(message);
    }

    public AgentFlowException(String message, Throwable cause) {
        super(message, cause);
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/AgentFlowType.java
================================================
package io.github.lnyocly.ai4j.agentflow;

public enum AgentFlowType {
    DIFY,
    COZE,
    N8N
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/AgentFlowUsage.java
================================================
package io.github.lnyocly.ai4j.agentflow;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder(toBuilder = true)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AgentFlowUsage {

    private Integer inputTokens;

    private Integer outputTokens;

    private Integer totalTokens;

    private Object raw;
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/AgentFlowChatEvent.java
================================================
package io.github.lnyocly.ai4j.agentflow.chat;

import io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder(toBuilder = true)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AgentFlowChatEvent {

    private String type;

    private String contentDelta;

    private String conversationId;

    private String messageId;

    private String taskId;

    private boolean done;

    private AgentFlowUsage usage;

    private Object raw;
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/AgentFlowChatListener.java
================================================
package io.github.lnyocly.ai4j.agentflow.chat;

public interface AgentFlowChatListener {

    void onEvent(AgentFlowChatEvent event);

    default void onOpen() {
    }

    default void onError(Throwable throwable) {
    }

    default void onComplete(AgentFlowChatResponse response) {
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/AgentFlowChatRequest.java
================================================
package io.github.lnyocly.ai4j.agentflow.chat;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;

import java.util.Collections;
import java.util.Map;

@Data
@Builder(toBuilder = true)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AgentFlowChatRequest {

    @NonNull
    private String prompt;

    @Builder.Default
    private Map<String, Object> inputs = Collections.emptyMap();

    private String userId;

    private String conversationId;

    @Builder.Default
    private Map<String, Object> metadata = Collections.emptyMap();

    @Builder.Default
    private Map<String, Object> extraBody = Collections.emptyMap();
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/AgentFlowChatResponse.java
================================================
package io.github.lnyocly.ai4j.agentflow.chat;

import io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder(toBuilder = true)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AgentFlowChatResponse {

    private String content;

    private String conversationId;

    private String messageId;

    private String taskId;

    private AgentFlowUsage usage;

    private Object raw;
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/AgentFlowChatService.java
================================================
package io.github.lnyocly.ai4j.agentflow.chat;

public interface AgentFlowChatService {

    AgentFlowChatResponse chat(AgentFlowChatRequest request) throws Exception;

    void chatStream(AgentFlowChatRequest request, AgentFlowChatListener listener) throws Exception;
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/CozeAgentFlowChatService.java
================================================
package io.github.lnyocly.ai4j.agentflow.chat;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import io.github.lnyocly.ai4j.agentflow.AgentFlowConfig;
import io.github.lnyocly.ai4j.agentflow.AgentFlowException;
import io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;
import io.github.lnyocly.ai4j.agentflow.support.AgentFlowSupport;
import io.github.lnyocly.ai4j.agentflow.trace.AgentFlowTraceContext;
import io.github.lnyocly.ai4j.service.Configuration;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

public class CozeAgentFlowChatService extends AgentFlowSupport implements AgentFlowChatService {

    public CozeAgentFlowChatService(Configuration configuration, AgentFlowConfig agentFlowConfig) {
        super(configuration, agentFlowConfig);
    }

    @Override
    public AgentFlowChatResponse chat(AgentFlowChatRequest request) throws Exception {
        AgentFlowTraceContext traceContext = startTrace("chat", false, request);
        try {
            JSONObject createResponse = executeObject(buildCreateRequest(request, false));
            assertCozeSuccess(createResponse);

            JSONObject createData = createResponse.getJSONObject("data");
            String chatId = createData == null ? null : createData.getString("id");
            String conversationId = firstNonBlank(
                    createData == null ? null : createData.getString("conversation_id"),
                    defaultConversationId(request.getConversationId())
            );
            if (isBlank(chatId)) {
                throw new AgentFlowException("Coze chat id is missing");
            }

            JSONObject chatData = pollChat(conversationId, chatId);
            String status = chatData.getString("status");
            if (!"completed".equals(status)) {
                throw new AgentFlowException("Coze chat finished with status: " + status);
            }

            JSONObject messageResponse = executeObject(buildMessageListRequest(conversationId, chatId));
            assertCozeSuccess(messageResponse);

            JSONArray messages = messageResponse.getJSONArray("data");
            StringBuilder content = new StringBuilder();
            String messageId = null;
            if (messages != null) {
                for (int i = messages.size() - 1; i >= 0; i--) {
                    JSONObject message = messages.getJSONObject(i);
                    if (message == null) {
                        continue;
                    }
                    if (!"assistant".equals(message.getString("role"))) {
                        continue;
                    }
                    String messageContent = message.getString("content");
                    if (!isBlank(messageContent)) {
                        if (content.length() > 0) {
                            content.insert(0, "\n");
                        }
                        content.insert(0, messageContent);
                        if (messageId == null) {
                            messageId = message.getString("id");
                        }
                    }
                }
            }

            Map<String, Object> raw = new LinkedHashMap<String, Object>();
            raw.put("chat", chatData);
            raw.put("messages", messages);

            AgentFlowChatResponse chatResponse = AgentFlowChatResponse.builder()
                    .content(content.toString())
                    .conversationId(conversationId)
                    .messageId(messageId)
                    .taskId(chatId)
                    .usage(usageFromCoze(chatData.getJSONObject("usage")))
                    .raw(raw)
                    .build();
            traceComplete(traceContext, chatResponse);
            return chatResponse;
        } catch (Exception ex) {
            traceError(traceContext, ex);
            throw ex;
        }
    }

    @Override
    public void chatStream(AgentFlowChatRequest request, final AgentFlowChatListener listener) throws Exception {
        if (listener == null) {
            throw new IllegalArgumentException("listener is required");
        }
        final AgentFlowTraceContext traceContext = startTrace("chat", true, request);
        Request httpRequest = buildCreateRequest(request, true);

        final CountDownLatch latch = new CountDownLatch(1);
        final AtomicReference<Throwable> failure = new AtomicReference<Throwable>();
        final AtomicReference<String> chatIdRef = new AtomicReference<String>();
        final AtomicReference<String> conversationIdRef = new AtomicReference<String>();
        final AtomicReference<String> messageIdRef = new AtomicReference<String>();
        final AtomicReference<AgentFlowUsage> usageRef = new AtomicReference<AgentFlowUsage>();
        final AtomicReference<AgentFlowChatResponse> completionRef = new AtomicReference<AgentFlowChatResponse>();
        final StringBuilder content = new StringBuilder();
        final AtomicBoolean closed = new AtomicBoolean(false);
        final AtomicBoolean sawDelta = new AtomicBoolean(false);

        eventSourceFactory.newEventSource(httpRequest, new EventSourceListener() {
            @Override
            public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) {
                listener.onOpen();
            }

            @Override
            public void onEvent(@NotNull EventSource eventSource,
                                @Nullable String id,
                                @Nullable String type,
                                @NotNull String data) {
                try {
                    String eventType = type;
                    JSONObject payload = parseObjectOrNull(data);

                    if ("done".equals(eventType)) {
                        AgentFlowChatEvent event = AgentFlowChatEvent.builder()
                                .type(eventType)
                                .conversationId(conversationIdRef.get())
                                .messageId(messageIdRef.get())
                                .taskId(chatIdRef.get())
                                .done(true)
                                .usage(usageRef.get())
                                .raw(data)
                                .build();
                        listener.onEvent(event);
                        traceEvent(traceContext, event);

                        AgentFlowChatResponse responsePayload = AgentFlowChatResponse.builder()
                                .content(content.toString())
                                .conversationId(conversationIdRef.get())
                                .messageId(messageIdRef.get())
                                .taskId(chatIdRef.get())
                                .usage(usageRef.get())
                                .raw(data)
                                .build();
                        completionRef.set(responsePayload);
                        listener.onComplete(responsePayload);
                        traceComplete(traceContext, responsePayload);
                        closed.set(true);
                        eventSource.cancel();
                        latch.countDown();
                        return;
                    }

                    if ("error".equals(eventType)) {
                        throw new AgentFlowException("Coze stream error: " + data);
                    }

                    String delta = null;
                    if (eventType != null && eventType.startsWith("conversation.chat.")) {
                        conversationIdRef.set(firstNonBlank(
                                payload == null ? null : payload.getString("conversation_id"),
                                conversationIdRef.get()
                        ));
                        chatIdRef.set(firstNonBlank(
                                payload == null ? null : payload.getString("id"),
                                chatIdRef.get()
                        ));
                        AgentFlowUsage usage = payload == null ? null : usageFromCoze(payload.getJSONObject("usage"));
                        if (usage != null) {
                            usageRef.set(usage);
                        }
                        if ("conversation.chat.failed".equals(eventType) || "conversation.chat.requires_action".equals(eventType)) {
                            throw new AgentFlowException("Coze chat status event: " + eventType);
                        }
                    } else if (eventType != null && eventType.startsWith("conversation.message.")) {
                        conversationIdRef.set(firstNonBlank(
                                payload == null ? null : payload.getString("conversation_id"),
                                conversationIdRef.get()
                        ));
                        chatIdRef.set(firstNonBlank(
                                payload == null ? null : payload.getString("chat_id"),
                                chatIdRef.get()
                        ));
                        messageIdRef.set(firstNonBlank(
                                payload == null ? null : payload.getString("id"),
                                messageIdRef.get()
                        ));
                        String contentValue = payload == null ? null : payload.getString("content");
                        if ("conversation.message.delta".equals(eventType)) {
                            delta = contentValue;
                            if (!isBlank(delta)) {
                                content.append(delta);
                                sawDelta.set(true);
                            }
                        } else if ("conversation.message.completed".equals(eventType)) {
                            if (!sawDelta.get() && !isBlank(contentValue)) {
                                content.append(contentValue);
                            }
                        }
                    }

                    AgentFlowChatEvent event = AgentFlowChatEvent.builder()
                            .type(eventType)
                            .contentDelta(delta)
                            .conversationId(conversationIdRef.get())
                            .messageId(messageIdRef.get())
                            .taskId(chatIdRef.get())
                            .usage(usageRef.get())
                            .raw(payload == null ? data : payload)
                            .build();
                    listener.onEvent(event);
                    traceEvent(traceContext, event);
                } catch (Throwable ex) {
                    failure.set(ex);
                    traceError(traceContext, ex);
                    listener.onError(ex);
                    closed.set(true);
                    eventSource.cancel();
                    latch.countDown();
                }
            }

            @Override
            public void onClosed(@NotNull EventSource eventSource) {
                if (closed.compareAndSet(false, true)) {
                    AgentFlowChatResponse responsePayload = completionRef.get();
                    if (responsePayload == null) {
                        responsePayload = AgentFlowChatResponse.builder()
                                .content(content.toString())
                                .conversationId(conversationIdRef.get())
                                .messageId(messageIdRef.get())
                                .taskId(chatIdRef.get())
                                .usage(usageRef.get())
                                .build();
                        completionRef.set(responsePayload);
                        listener.onComplete(responsePayload);
                        traceComplete(traceContext, responsePayload);
                    }
                    latch.countDown();
                }
            }

            @Override
            public void onFailure(@NotNull EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
                Throwable error = t;
                if (error == null && response != null) {
                    error = new AgentFlowException("Coze stream failed: HTTP " + response.code());
                }
                if (error == null) {
                    error = new AgentFlowException("Coze stream failed");
                }
                failure.set(error);
                traceError(traceContext, error);
                listener.onError(error);
                closed.set(true);
                latch.countDown();
            }
        });

        if (!latch.await(pollTimeoutMillis(), TimeUnit.MILLISECONDS)) {
            throw new AgentFlowException("Coze stream timed out");
        }
        if (failure.get() != null) {
            if (failure.get() instanceof Exception) {
                throw (Exception) failure.get();
            }
            throw new AgentFlowException("Coze stream failed", failure.get());
        }
    }

    private JSONObject pollChat(String conversationId, String chatId) throws Exception {
        long deadline = System.currentTimeMillis() + pollTimeoutMillis();
        while (true) {
            String url = appendQuery(
                    joinedUrl(requireBaseUrl(), "v3/chat/retrieve"),
                    query(conversationId, chatId)
            );
            JSONObject retrieveResponse = executeObject(jsonRequestBuilder(url).get().build());
            assertCozeSuccess(retrieveResponse);
            JSONObject chatData = retrieveResponse.getJSONObject("data");
            String status = chatData == null ? null : chatData.getString("status");
            if ("completed".equals(status) || "failed".equals(status) || "canceled".equals(status) || "requires_action".equals(status)) {
                return chatData == null ? new JSONObject() : chatData;
            }
            if (System.currentTimeMillis() >= deadline) {
                throw new AgentFlowException("Coze chat poll timed out");
            }
            sleep(pollIntervalMillis());
        }
    }

    private Request buildCreateRequest(AgentFlowChatRequest request, boolean stream) {
        String conversationId = defaultConversationId(request.getConversationId());
        String url = appendQuery(
                joinedUrl(requireBaseUrl(), "v3/chat"),
                queryConversation(conversationId)
        );
        return jsonRequestBuilder(url).post(jsonBody(buildCreateBody(request, stream))).build();
    }

    private JSONObject buildCreateBody(AgentFlowChatRequest request, boolean stream) {
        JSONObject body = new JSONObject();
        body.put("bot_id", requireBotId());
        body.put("user_id", defaultUserId(request.getUserId()));
        body.put("stream", stream);
        body.put("additional_messages", Collections.singletonList(userMessage(request.getPrompt())));
        if (request.getInputs() != null && !request.getInputs().isEmpty()) {
            body.put("parameters", request.getInputs());
        }
        if (request.getMetadata() != null && !request.getMetadata().isEmpty()) {
            body.put("meta_data", toStringMap(request.getMetadata()));
        }
        if (!stream && !body.containsKey("auto_save_history")) {
            body.put("auto_save_history", true);
        }
        if (request.getExtraBody() != null && !request.getExtraBody().isEmpty()) {
            body.putAll(request.getExtraBody());
        }
        return body;
    }

    private Request buildMessageListRequest(String conversationId, String chatId) {
        String url = appendQuery(
                joinedUrl(requireBaseUrl(), "v1/conversation/message/list"),
                queryConversation(conversationId)
        );
        JSONObject body = new JSONObject();
        body.put("conversation_id", conversationId);
        body.put("chat_id", chatId);
        body.put("order", "asc");
        body.put("limit", 50);
        if (!isBlank(agentFlowConfig.getBotId())) {
            body.put("bot_id", agentFlowConfig.getBotId());
        }
        return jsonRequestBuilder(url).post(jsonBody(body)).build();
    }

    private JSONObject userMessage(String prompt) {
        JSONObject message = new JSONObject();
        message.put("role", "user");
        message.put("type", "question");
        message.put("content", prompt);
        message.put("content_type", "text");
        return message;
    }

    private JSONObject parseObjectOrNull(String data) {
        if (isBlank(data)) {
            return null;
        }
        try {
            Object parsed = JSON.parse(data);
            return parsed instanceof JSONObject ? (JSONObject) parsed : null;
        } catch (Exception ex) {
            return null;
        }
    }

    private Map<String, String> queryConversation(String conversationId) {
        Map<String, String> values = new LinkedHashMap<String, String>();
        if (!isBlank(conversationId)) {
            values.put("conversation_id", conversationId);
        }
        return values;
    }

    private Map<String, String> query(String conversationId, String chatId) {
        Map<String, String> values = queryConversation(conversationId);
        if (!isBlank(chatId)) {
            values.put("chat_id", chatId);
        }
        return values;
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/DifyAgentFlowChatService.java
================================================
package io.github.lnyocly.ai4j.agentflow.chat;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import io.github.lnyocly.ai4j.agentflow.AgentFlowConfig;
import io.github.lnyocly.ai4j.agentflow.AgentFlowException;
import io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;
import io.github.lnyocly.ai4j.agentflow.support.AgentFlowSupport;
import io.github.lnyocly.ai4j.agentflow.trace.AgentFlowTraceContext;
import io.github.lnyocly.ai4j.service.Configuration;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

public class DifyAgentFlowChatService extends AgentFlowSupport implements AgentFlowChatService {

    public DifyAgentFlowChatService(Configuration configuration, AgentFlowConfig agentFlowConfig) {
        super(configuration, agentFlowConfig);
    }

    @Override
    public AgentFlowChatResponse chat(AgentFlowChatRequest request) throws Exception {
        AgentFlowTraceContext traceContext = startTrace("chat", false, request);
        try {
            JSONObject body = buildRequestBody(request, "blocking");
            String url = joinedUrl(requireBaseUrl(), "v1/chat-messages");
            JSONObject response = executeObject(jsonRequestBuilder(url).post(jsonBody(body)).build());
            AgentFlowChatResponse chatResponse = mapBlockingResponse(response);
            traceComplete(traceContext, chatResponse);
            return chatResponse;
        } catch (Exception ex) {
            traceError(traceContext, ex);
            throw ex;
        }
    }

    @Override
    public void chatStream(AgentFlowChatRequest request, final AgentFlowChatListener listener) throws Exception {
        if (listener == null) {
            throw new IllegalArgumentException("listener is required");
        }
        final AgentFlowTraceContext traceContext = startTrace("chat", true, request);
        JSONObject body = buildRequestBody(request, "streaming");
        String url = joinedUrl(requireBaseUrl(), "v1/chat-messages");
        Request httpRequest = jsonRequestBuilder(url).post(jsonBody(body)).build();

        final CountDownLatch latch = new CountDownLatch(1);
        final AtomicReference<Throwable> failure = new AtomicReference<Throwable>();
        final AtomicReference<AgentFlowChatResponse> completion = new AtomicReference<AgentFlowChatResponse>();
        final AtomicReference<String> conversationIdRef = new AtomicReference<String>();
        final AtomicReference<String> messageIdRef = new AtomicReference<String>();
        final AtomicReference<String> taskIdRef = new AtomicReference<String>();
        final AtomicReference<AgentFlowUsage> usageRef = new AtomicReference<AgentFlowUsage>();
        final StringBuilder content = new StringBuilder();
        final AtomicBoolean closed = new AtomicBoolean(false);

        eventSourceFactory.newEventSource(httpRequest, new EventSourceListener() {
            @Override
            public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) {
                listener.onOpen();
            }

            @Override
            public void onEvent(@NotNull EventSource eventSource,
                                @Nullable String id,
                                @Nullable String type,
                                @NotNull String data) {
                try {
                    JSONObject payload = parseObjectOrNull(data);
                    String eventType = firstNonBlank(type, payload == null ? null : payload.getString("event"));
                    if (isBlank(eventType) || "ping".equals(eventType)) {
                        return;
                    }

                    String conversationId = payload == null ? null : payload.getString("conversation_id");
                    String messageId = payload == null ? null : firstNonBlank(payload.getString("message_id"), payload.getString("id"));
                    String taskId = payload == null ? null : payload.getString("task_id");
                    if (!isBlank(conversationId)) {
                        conversationIdRef.set(conversationId);
                    }
                    if (!isBlank(messageId)) {
                        messageIdRef.set(messageId);
                    }
                    if (!isBlank(taskId)) {
                        taskIdRef.set(taskId);
                    }

                    AgentFlowUsage usage = payload == null ? null : usageFromDify(metadataUsage(payload));
                    if (usage != null) {
                        usageRef.set(usage);
                    }

                    String delta = null;
                    if ("message".equals(eventType) || "agent_message".equals(eventType)) {
                        delta = payload == null ? null : payload.getString("answer");
                        if (!isBlank(delta)) {
                            content.append(delta);
                        }
                    }

                    boolean done = "message_end".equals(eventType);
                    AgentFlowChatEvent event = AgentFlowChatEvent.builder()
                            .type(eventType)
                            .contentDelta(delta)
                            .conversationId(conversationIdRef.get())
                            .messageId(messageIdRef.get())
                            .taskId(taskIdRef.get())
                            .done(done)
                            .usage(usageRef.get())
                            .raw(payload == null ? data : payload)
                            .build();
                    listener.onEvent(event);
                    traceEvent(traceContext, event);

                    if ("error".equals(eventType)) {
                        throw new AgentFlowException("Dify stream error: " + (payload == null ? data : payload.toJSONString()));
                    }
                    if (done) {
                        AgentFlowChatResponse responsePayload = AgentFlowChatResponse.builder()
                                .content(content.toString())
                                .conversationId(conversationIdRef.get())
                                .messageId(messageIdRef.get())
                                .taskId(taskIdRef.get())
                                .usage(usageRef.get())
                                .raw(payload)
                                .build();
                        completion.set(responsePayload);
                        listener.onComplete(responsePayload);
                        traceComplete(traceContext, responsePayload);
                        closed.set(true);
                        eventSource.cancel();
                        latch.countDown();
                    }
                } catch (Throwable ex) {
                    failure.set(ex);
                    traceError(traceContext, ex);
                    listener.onError(ex);
                    closed.set(true);
                    eventSource.cancel();
                    latch.countDown();
                }
            }

            @Override
            public void onClosed(@NotNull EventSource eventSource) {
                if (closed.compareAndSet(false, true)) {
                    AgentFlowChatResponse responsePayload = completion.get();
                    if (responsePayload == null) {
                        responsePayload = AgentFlowChatResponse.builder()
                                .content(content.toString())
                                .conversationId(conversationIdRef.get())
                                .messageId(messageIdRef.get())
                                .taskId(taskIdRef.get())
                                .usage(usageRef.get())
                                .build();
                        completion.set(responsePayload);
                        listener.onComplete(responsePayload);
                        traceComplete(traceContext, responsePayload);
                    }
                    latch.countDown();
                }
            }

            @Override
            public void onFailure(@NotNull EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
                Throwable error = t;
                if (error == null && response != null) {
                    error = new AgentFlowException("Dify stream failed: HTTP " + response.code());
                }
                if (error == null) {
                    error = new AgentFlowException("Dify stream failed");
                }
                failure.set(error);
                traceError(traceContext, error);
                listener.onError(error);
                closed.set(true);
                latch.countDown();
            }
        });

        if (!latch.await(pollTimeoutMillis(), TimeUnit.MILLISECONDS)) {
            throw new AgentFlowException("Dify stream timed out");
        }
        if (failure.get() != null) {
            if (failure.get() instanceof Exception) {
                throw (Exception) failure.get();
            }
            throw new AgentFlowException("Dify stream failed", failure.get());
        }
    }

    private JSONObject buildRequestBody(AgentFlowChatRequest request, String responseMode) {
        JSONObject body = new JSONObject();
        body.put("query", request.getPrompt());
        body.put("inputs", request.getInputs() == null ? Collections.emptyMap() : request.getInputs());
        body.put("user", defaultUserId(request.getUserId()));
        body.put("response_mode", responseMode);
        String conversationId = defaultConversationId(request.getConversationId());
        if (!isBlank(conversationId)) {
            body.put("conversation_id", conversationId);
        }
        if (request.getExtraBody() != null && !request.getExtraBody().isEmpty()) {
            body.putAll(request.getExtraBody());
        }
        return body;
    }

    private AgentFlowChatResponse mapBlockingResponse(JSONObject response) {
        return AgentFlowChatResponse.builder()
                .content(firstNonBlank(response.getString("answer"), response.getString("message")))
                .conversationId(response.getString("conversation_id"))
                .messageId(firstNonBlank(response.getString("message_id"), response.getString("id")))
                .taskId(response.getString("task_id"))
                .usage(usageFromDify(metadataUsage(response)))
                .raw(response)
                .build();
    }

    private JSONObject metadataUsage(JSONObject payload) {
        JSONObject metadata = payload == null ? null : payload.getJSONObject("metadata");
        return metadata == null ? null : metadata.getJSONObject("usage");
    }

    private JSONObject parseObjectOrNull(String data) {
        if (isBlank(data)) {
            return null;
        }
        try {
            Object parsed = JSON.parse(data);
            return parsed instanceof JSONObject ? (JSONObject) parsed : null;
        } catch (Exception ex) {
            return null;
        }
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/support/AgentFlowSupport.java
================================================
package io.github.lnyocly.ai4j.agentflow.support;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import io.github.lnyocly.ai4j.agentflow.AgentFlowConfig;
import io.github.lnyocly.ai4j.agentflow.AgentFlowException;
import io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;
import io.github.lnyocly.ai4j.agentflow.trace.AgentFlowTraceContext;
import io.github.lnyocly.ai4j.agentflow.trace.AgentFlowTraceListener;
import io.github.lnyocly.ai4j.constant.Constants;
import io.github.lnyocly.ai4j.network.UrlUtils;
import io.github.lnyocly.ai4j.service.Configuration;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.sse.EventSource;

import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public abstract class AgentFlowSupport {

    protected static final MediaType JSON_MEDIA_TYPE = MediaType.get(Constants.APPLICATION_JSON);

    protected final Configuration configuration;
    protected final AgentFlowConfig agentFlowConfig;
    protected final OkHttpClient okHttpClient;
    protected final EventSource.Factory eventSourceFactory;

    protected AgentFlowSupport(Configuration configuration, AgentFlowConfig agentFlowConfig) {
        if (configuration == null) {
            throw new IllegalArgumentException("configuration is required");
        }
        if (configuration.getOkHttpClient() == null) {
            throw new IllegalArgumentException("OkHttpClient configuration is required");
        }
        if (agentFlowConfig == null) {
            throw new IllegalArgumentException("agentFlowConfig is required");
        }
        this.configuration = configuration;
        this.agentFlowConfig = agentFlowConfig;
        this.okHttpClient = configuration.getOkHttpClient();
        this.eventSourceFactory = configuration.createRequestFactory();
    }

    protected String defaultUserId(String requestUserId) {
        if (!isBlank(requestUserId)) {
            return requestUserId;
        }
        if (!isBlank(agentFlowConfig.getUserId())) {
            return agentFlowConfig.getUserId();
        }
        return "default-user";
    }

    protected String defaultConversationId(String requestConversationId) {
        if (!isBlank(requestConversationId)) {
            return requestConversationId;
        }
        return agentFlowConfig.getConversationId();
    }

    protected String requireBaseUrl() {
        if (isBlank(agentFlowConfig.getBaseUrl())) {
            throw new IllegalArgumentException("baseUrl is required");
        }
        return agentFlowConfig.getBaseUrl();
    }

    protected String requireWebhookUrl() {
        if (isBlank(agentFlowConfig.getWebhookUrl())) {
            throw new IllegalArgumentException("webhookUrl is required");
        }
        return agentFlowConfig.getWebhookUrl();
    }

    protected String requireApiKey() {
        if (isBlank(agentFlowConfig.getApiKey())) {
            throw new IllegalArgumentException("apiKey is required");
        }
        return agentFlowConfig.getApiKey();
    }

    protected String requireBotId() {
        if (isBlank(agentFlowConfig.getBotId())) {
            throw new IllegalArgumentException("botId is required");
        }
        return agentFlowConfig.getBotId();
    }

    protected String requireWorkflowId(String requestWorkflowId) {
        if (!isBlank(requestWorkflowId)) {
            return requestWorkflowId;
        }
        if (!isBlank(agentFlowConfig.getWorkflowId())) {
            return agentFlowConfig.getWorkflowId();
        }
        throw new IllegalArgumentException("workflowId is required");
    }

    protected String joinedUrl(String baseUrl, String path) {
        return UrlUtils.concatUrl(baseUrl, path);
    }

    protected String appendQuery(String url, Map<String, String> queryParameters) {
        HttpUrl parsed = HttpUrl.parse(url);
        if (parsed == null) {
            throw new IllegalArgumentException("Invalid URL: " + url);
        }
        HttpUrl.Builder builder = parsed.newBuilder();
        if (queryParameters != null) {
            for (Map.Entry<String, String> entry : queryParameters.entrySet()) {
                if (!isBlank(entry.getValue())) {
                    builder.addQueryParameter(entry.getKey(), entry.getValue());
                }
            }
        }
        return builder.build().toString();
    }

    protected RequestBody jsonBody(Object body) {
        return RequestBody.create(JSON.toJSONString(body), JSON_MEDIA_TYPE);
    }

    protected Request.Builder jsonRequestBuilder(String url) {
        Request.Builder builder = new Request.Builder().url(url);
        builder.header("Content-Type", Constants.APPLICATION_JSON);
        if (!isBlank(agentFlowConfig.getApiKey())) {
            builder.header("Authorization", "Bearer " + agentFlowConfig.getApiKey());
        }
        if (agentFlowConfig.getHeaders() != null) {
            for (Map.Entry<String, String> entry : agentFlowConfig.getHeaders().entrySet()) {
                if (!isBlank(entry.getKey()) && entry.getValue() != null) {
                    builder.header(entry.getKey(), entry.getValue());
                }
            }
        }
        return builder;
    }

    protected String execute(Request request) throws IOException {
        try (Response response = okHttpClient.newCall(request).execute()) {
            return readResponse(request, response);
        }
    }

    protected JSONObject executeObject(Request request) throws IOException {
        String body = execute(request);
        if (isBlank(body)) {
            return new JSONObject();
        }
        Object parsed = JSON.parse(body);
        if (parsed instanceof JSONObject) {
            return (JSONObject) parsed;
        }
        throw new AgentFlowException("Expected JSON object response but got: " + body);
    }

    protected Object parseJsonOrText(String body) {
        if (isBlank(body)) {
            return null;
        }
        try {
            return JSON.parse(body);
        } catch (Exception ex) {
            return body;
        }
    }

    protected String readResponse(Request request, Response response) throws IOException {
        ResponseBody body = response.body();
        String content = body == null ? "" : body.string();
        if (!response.isSuccessful()) {
            throw new AgentFlowException("HTTP " + response.code() + " calling " + request.url() + ": " + abbreviate(content));
        }
        return content;
    }

    protected void assertCozeSuccess(JSONObject response) {
        Integer code = response == null ? null : response.getInteger("code");
        if (code != null && code.intValue() != 0) {
            throw new AgentFlowException("Coze request failed: code=" + code + ", msg=" + response.getString("msg"));
        }
    }

    protected Map<String, Object> mutableMap(Map<String, Object> source) {
        if (source == null || source.isEmpty()) {
            return new LinkedHashMap<String, Object>();
        }
        return new LinkedHashMap<String, Object>(source);
    }

    protected Map<String, String> toStringMap(Map<String, Object> source) {
        if (source == null || source.isEmpty()) {
            return Collections.emptyMap();
        }
        Map<String, String> result = new LinkedHashMap<String, String>();
        for (Map.Entry<String, Object> entry : source.entrySet()) {
            if (entry.getKey() != null && entry.getValue() != null) {
                result.put(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }
        return result;
    }

    protected String extractText(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof String) {
            return (String) value;
        }
        if (value instanceof JSONObject) {
            JSONObject jsonObject = (JSONObject) value;
            String direct = firstNonBlank(
                    jsonObject.getString("answer"),
                    jsonObject.getString("output"),
                    jsonObject.getString("text"),
                    jsonObject.getString("content"),
                    jsonObject.getString("result"),
                    jsonObject.getString("message")
            );
            if (!isBlank(direct)) {
                return direct;
            }
            if (jsonObject.size() == 1) {
                Map.Entry<String, Object> entry = jsonObject.entrySet().iterator().next();
                return extractText(entry.getValue());
            }
            return JSON.toJSONString(jsonObject);
        }
        return String.valueOf(value);
    }

    protected AgentFlowUsage usageFromDify(JSONObject usage) {
        if (usage == null || usage.isEmpty()) {
            return null;
        }
        return AgentFlowUsage.builder()
                .inputTokens(usage.getInteger("prompt_tokens"))
                .outputTokens(usage.getInteger("completion_tokens"))
                .totalTokens(usage.getInteger("total_tokens"))
                .raw(usage)
                .build();
    }

    protected AgentFlowUsage usageFromCoze(JSONObject usage) {
        if (usage == null || usage.isEmpty()) {
            return null;
        }
        return AgentFlowUsage.builder()
                .inputTokens(firstNonNullInteger(usage.getInteger("input_tokens"), usage.getInteger("input_count")))
                .outputTokens(firstNonNullInteger(usage.getInteger("output_tokens"), usage.getInteger("output_count")))
                .totalTokens(usage.getInteger("token_count"))
                .raw(usage)
                .build();
    }

    protected Integer firstNonNullInteger(Integer first, Integer second) {
        return first != null ? first : second;
    }

    protected String firstNonBlank(String first, String second) {
        return firstNonBlank(first, second, null, null, null, null);
    }

    protected String firstNonBlank(String first,
                                   String second,
                                   String third,
                                   String fourth,
                                   String fifth,
                                   String sixth) {
        String[] values = new String[]{first, second, third, fourth, fifth, sixth};
        for (String value : values) {
            if (!isBlank(value)) {
                return value;
            }
        }
        return null;
    }

    protected long pollIntervalMillis() {
        Long value = agentFlowConfig.getPollIntervalMillis();
        return value == null || value.longValue() <= 0L ? 1_000L : value.longValue();
    }

    protected long pollTimeoutMillis() {
        Long value = agentFlowConfig.getPollTimeoutMillis();
        return value == null || value.longValue() <= 0L ? 60_000L : value.longValue();
    }

    protected void sleep(long millis) throws InterruptedException {
        if (millis > 0L) {
            Thread.sleep(millis);
        }
    }

    protected String abbreviate(String value) {
        if (value == null) {
            return null;
        }
        if (value.length() <= 500) {
            return value;
        }
        return value.substring(0, 500) + "...";
    }

    protected boolean isBlank(String value) {
        return value == null || value.trim().isEmpty();
    }

    protected AgentFlowTraceContext startTrace(String operation, boolean streaming, Object request) {
        AgentFlowTraceContext context = AgentFlowTraceContext.builder()
                .executionId(UUID.randomUUID().toString())
                .type(agentFlowConfig.getType())
                .operation(operation)
                .streaming(streaming)
                .startedAt(System.currentTimeMillis())
                .baseUrl(agentFlowConfig.getBaseUrl())
                .webhookUrl(agentFlowConfig.getWebhookUrl())
                .botId(agentFlowConfig.getBotId())
                .workflowId(agentFlowConfig.getWorkflowId())
                .appId(agentFlowConfig.getAppId())
                .configuredUserId(agentFlowConfig.getUserId())
                .configuredConversationId(agentFlowConfig.getConversationId())
                .request(request)
                .build();
        notifyTraceStart(context);
        return context;
    }

    protected void traceEvent(AgentFlowTraceContext context, Object event) {
        List<AgentFlowTraceListener> listeners = traceListeners();
        if (context == null || event == null || listeners.isEmpty()) {
            return;
        }
        for (AgentFlowTraceListener listener : listeners) {
            if (listener == null) {
                continue;
            }
            try {
                listener.onEvent(context, event);
            } catch (Throwable ignored) {
                // Trace listeners must never break the primary AgentFlow call path.
            }
        }
    }

    protected void traceComplete(AgentFlowTraceContext context, Object response) {
        List<AgentFlowTraceListener> listeners = traceListeners();
        if (context == null || listeners.isEmpty()) {
            return;
        }
        for (AgentFlowTraceListener listener : listeners) {
            if (listener == null) {
                continue;
            }
            try {
                listener.onComplete(context, response);
            } catch (Throwable ignored) {
                // Trace listeners must never break the primary AgentFlow call path.
            }
        }
    }

    protected void traceError(AgentFlowTraceContext context, Throwable throwable) {
        List<AgentFlowTraceListener> listeners = traceListeners();
        if (context == null || throwable == null || listeners.isEmpty()) {
            return;
        }
        for (AgentFlowTraceListener listener : listeners) {
            if (listener == null) {
                continue;
            }
            try {
                listener.onError(context, throwable);
            } catch (Throwable ignored) {
                // Trace listeners must never break the primary AgentFlow call path.
            }
        }
    }

    private void notifyTraceStart(AgentFlowTraceContext context) {
        List<AgentFlowTraceListener> listeners = traceListeners();
        if (context == null || listeners.isEmpty()) {
            return;
        }
        for (AgentFlowTraceListener listener : listeners) {
            if (listener == null) {
                continue;
            }
            try {
                listener.onStart(context);
            } catch (Throwable ignored) {
                // Trace listeners must never break the primary AgentFlow call path.
            }
        }
    }

    private List<AgentFlowTraceListener> traceListeners() {
        List<AgentFlowTraceListener> listeners = agentFlowConfig.getTraceListeners();
        return listeners == null ? Collections.<AgentFlowTraceListener>emptyList() : listeners;
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/trace/AgentFlowTraceContext.java
================================================
package io.github.lnyocly.ai4j.agentflow.trace;

import io.github.lnyocly.ai4j.agentflow.AgentFlowType;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder(toBuilder = true)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AgentFlowTraceContext {

    private String executionId;

    private AgentFlowType type;

    private String operation;

    private boolean streaming;

    private long startedAt;

    private String baseUrl;

    private String webhookUrl;

    private String botId;

    private String workflowId;

    private String appId;

    private String configuredUserId;

    private String configuredConversationId;

    private Object request;
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/trace/AgentFlowTraceListener.java
================================================
package io.github.lnyocly.ai4j.agentflow.trace;

public interface AgentFlowTraceListener {

    default void onStart(AgentFlowTraceContext context) {
    }

    default void onEvent(AgentFlowTraceContext context, Object event) {
    }

    default void onComplete(AgentFlowTraceContext context, Object response) {
    }

    default void onError(AgentFlowTraceContext context, Throwable throwable) {
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/AgentFlowWorkflowEvent.java
================================================
package io.github.lnyocly.ai4j.agentflow.workflow;

import io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Collections;
import java.util.Map;

@Data
@Builder(toBuilder = true)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AgentFlowWorkflowEvent {

    private String type;

    private String status;

    private String outputText;

    @Builder.Default
    private Map<String, Object> outputs = Collections.emptyMap();

    private String taskId;

    private String workflowRunId;

    private boolean done;

    private AgentFlowUsage usage;

    private Object raw;
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/AgentFlowWorkflowListener.java
================================================
package io.github.lnyocly.ai4j.agentflow.workflow;

public interface AgentFlowWorkflowListener {

    void onEvent(AgentFlowWorkflowEvent event);

    default void onOpen() {
    }

    default void onError(Throwable throwable) {
    }

    default void onComplete(AgentFlowWorkflowResponse response) {
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/AgentFlowWorkflowRequest.java
================================================
package io.github.lnyocly.ai4j.agentflow.workflow;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Collections;
import java.util.Map;

@Data
@Builder(toBuilder = true)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AgentFlowWorkflowRequest {

    @Builder.Default
    private Map<String, Object> inputs = Collections.emptyMap();

    private String userId;

    private String workflowId;

    @Builder.Default
    private Map<String, Object> metadata = Collections.emptyMap();

    @Builder.Default
    private Map<String, Object> extraBody = Collections.emptyMap();
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/AgentFlowWorkflowResponse.java
================================================
package io.github.lnyocly.ai4j.agentflow.workflow;

import io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Collections;
import java.util.Map;

@Data
@Builder(toBuilder = true)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AgentFlowWorkflowResponse {

    private String status;

    private String outputText;

    @Builder.Default
    private Map<String, Object> outputs = Collections.emptyMap();

    private String taskId;

    private String workflowRunId;

    private AgentFlowUsage usage;

    private Object raw;
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/AgentFlowWorkflowService.java
================================================
package io.github.lnyocly.ai4j.agentflow.workflow;

public interface AgentFlowWorkflowService {

    AgentFlowWorkflowResponse run(AgentFlowWorkflowRequest request) throws Exception;

    void runStream(AgentFlowWorkflowRequest request, AgentFlowWorkflowListener listener) throws Exception;
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/CozeAgentFlowWorkflowService.java
================================================
package io.github.lnyocly.ai4j.agentflow.workflow;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import io.github.lnyocly.ai4j.agentflow.AgentFlowConfig;
import io.github.lnyocly.ai4j.agentflow.AgentFlowException;
import io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;
import io.github.lnyocly.ai4j.agentflow.support.AgentFlowSupport;
import io.github.lnyocly.ai4j.agentflow.trace.AgentFlowTraceContext;
import io.github.lnyocly.ai4j.service.Configuration;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

public class CozeAgentFlowWorkflowService extends AgentFlowSupport implements AgentFlowWorkflowService {

    public CozeAgentFlowWorkflowService(Configuration configuration, AgentFlowConfig agentFlowConfig) {
        super(configuration, agentFlowConfig);
    }

    @Override
    public AgentFlowWorkflowResponse run(AgentFlowWorkflowRequest request) throws Exception {
        AgentFlowTraceContext traceContext = startTrace("workflow", false, request);
        try {
            JSONObject response = executeObject(buildRunRequest(request, false));
            assertCozeSuccess(response);

            Object dataValue = response.get("data");
            Object parsedData = parseWorkflowData(dataValue);
            Map<String, Object> outputs = parsedData instanceof JSONObject
                    ? new LinkedHashMap<String, Object>((JSONObject) parsedData)
                    : Collections.<String, Object>emptyMap();

            AgentFlowWorkflowResponse workflowResponse = AgentFlowWorkflowResponse.builder()
                    .status("completed")
                    .outputText(extractText(parsedData))
                    .outputs(outputs)
                    .workflowRunId(response.getString("execute_id"))
                    .usage(usageFromCoze(response.getJSONObject("usage")))
                    .raw(response)
                    .build();
            traceComplete(traceContext, workflowResponse);
            return workflowResponse;
        } catch (Exception ex) {
            traceError(traceContext, ex);
            throw ex;
        }
    }

    @Override
    public void runStream(AgentFlowWorkflowRequest request, final AgentFlowWorkflowListener listener) throws Exception {
        if (listener == null) {
            throw new IllegalArgumentException("listener is required");
        }
        final AgentFlowTraceContext traceContext = startTrace("workflow", true, request);

        Request httpRequest = buildRunRequest(request, true);
        final CountDownLatch latch = new CountDownLatch(1);
        final AtomicReference<Throwable> failure = new AtomicReference<Throwable>();
        final AtomicReference<AgentFlowWorkflowResponse> completion = new AtomicReference<AgentFlowWorkflowResponse>();
        final AtomicReference<AgentFlowUsage> usageRef = new AtomicReference<AgentFlowUsage>();
        final StringBuilder content = new StringBuilder();
        final AtomicBoolean closed = new AtomicBoolean(false);

        eventSourceFactory.newEventSource(httpRequest, new EventSourceListener() {
            @Override
            public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) {
                listener.onOpen();
            }

            @Override
            public void onEvent(@NotNull EventSource eventSource,
                                @Nullable String id,
                                @Nullable String type,
                                @NotNull String data) {
                try {
                    String eventType = type;
                    JSONObject payload = parseObjectOrNull(data);
                    boolean done = false;
                    String outputText = null;

                    if ("Message".equals(eventType)) {
                        outputText = payload == null ? null : payload.getString("content");
                        if (!isBlank(outputText)) {
                            content.append(outputText);
                        }
                        AgentFlowUsage usage = payload == null ? null : usageFromCoze(payload.getJSONObject("usage"));
                        if (usage != null) {
                            usageRef.set(usage);
                        }
                    } else if ("Interrupt".equals(eventType)) {
                        throw new AgentFlowException("Coze workflow interrupted: " + data);
                    } else if ("Error".equals(eventType)) {
                        throw new AgentFlowException("Coze workflow stream error: " + data);
                    } else if ("Done".equals(eventType)) {
                        done = true;
                    }

                    AgentFlowWorkflowEvent event = AgentFlowWorkflowEvent.builder()
                            .type(eventType)
                            .status(done ? "completed" : null)
                            .outputText(outputText)
                            .done(done)
                            .usage(usageRef.get())
                            .raw(payload == null ? data : payload)
                            .build();
                    listener.onEvent(event);
                    traceEvent(traceContext, event);

                    if (done) {
                        AgentFlowWorkflowResponse responsePayload = AgentFlowWorkflowResponse.builder()
                                .status("completed")
                                .outputText(content.toString())
                                .usage(usageRef.get())
                                .raw(payload == null ? data : payload)
                                .build();
                        completion.set(responsePayload);
                        listener.onComplete(responsePayload);
                        traceComplete(traceContext, responsePayload);
                        closed.set(true);
                        eventSource.cancel();
                        latch.countDown();
                    }
                } catch (Throwable ex) {
                    failure.set(ex);
                    traceError(traceContext, ex);
                    listener.onError(ex);
                    closed.set(true);
                    eventSource.cancel();
                    latch.countDown();
                }
            }

            @Override
            public void onClosed(@NotNull EventSource eventSource) {
                if (closed.compareAndSet(false, true)) {
                    AgentFlowWorkflowResponse responsePayload = completion.get();
                    if (responsePayload == null) {
                        responsePayload = AgentFlowWorkflowResponse.builder()
                                .status("completed")
                                .outputText(content.toString())
                                .usage(usageRef.get())
                                .build();
                        completion.set(responsePayload);
                        listener.onComplete(responsePayload);
                        traceComplete(traceContext, responsePayload);
                    }
                    latch.countDown();
                }
            }

            @Override
            public void onFailure(@NotNull EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
                Throwable error = t;
                if (error == null && response != null) {
                    error = new AgentFlowException("Coze workflow stream failed: HTTP " + response.code());
                }
                if (error == null) {
                    error = new AgentFlowException("Coze workflow stream failed");
                }
                failure.set(error);
                traceError(traceContext, error);
                listener.onError(error);
                closed.set(true);
                latch.countDown();
            }
        });

        if (!latch.await(pollTimeoutMillis(), TimeUnit.MILLISECONDS)) {
            throw new AgentFlowException("Coze workflow stream timed out");
        }
        if (failure.get() != null) {
            if (failure.get() instanceof Exception) {
                throw (Exception) failure.get();
            }
            throw new AgentFlowException("Coze workflow stream failed", failure.get());
        }
    }

    private Request buildRunRequest(AgentFlowWorkflowRequest request, boolean stream) {
        String path = stream ? "v1/workflow/stream_run" : "v1/workflow/run";
        String url = joinedUrl(requireBaseUrl(), path);
        return jsonRequestBuilder(url).post(jsonBody(buildRequestBody(request))).build();
    }

    private JSONObject buildRequestBody(AgentFlowWorkflowRequest request) {
        JSONObject body = new JSONObject();
        body.put("workflow_id", requireWorkflowId(request.getWorkflowId()));
        body.put("parameters", request.getInputs() == null ? Collections.emptyMap() : request.getInputs());
        if (!isBlank(agentFlowConfig.getBotId())) {
            body.put("bot_id", agentFlowConfig.getBotId());
        }
        if (!isBlank(agentFlowConfig.getAppId())) {
            body.put("app_id", agentFlowConfig.getAppId());
        }
        if (request.getMetadata() != null && !request.getMetadata().isEmpty()) {
            body.put("ext", toStringMap(request.getMetadata()));
        }
        if (request.getExtraBody() != null && !request.getExtraBody().isEmpty()) {
            body.putAll(request.getExtraBody());
        }
        return body;
    }

    private Object parseWorkflowData(Object dataValue) {
        if (dataValue == null) {
            return null;
        }
        if (!(dataValue instanceof String)) {
            return dataValue;
        }
        String text = (String) dataValue;
        if (isBlank(text)) {
            return null;
        }
        try {
            return JSON.parse(text);
        } catch (Exception ex) {
            return text;
        }
    }

    private JSONObject parseObjectOrNull(String data) {
        if (isBlank(data)) {
            return null;
        }
        try {
            Object parsed = JSON.parse(data);
            return parsed instanceof JSONObject ? (JSONObject) parsed : null;
        } catch (Exception ex) {
            return null;
        }
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/DifyAgentFlowWorkflowService.java
================================================
package io.github.lnyocly.ai4j.agentflow.workflow;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import io.github.lnyocly.ai4j.agentflow.AgentFlowConfig;
import io.github.lnyocly.ai4j.agentflow.AgentFlowException;
import io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;
import io.github.lnyocly.ai4j.agentflow.support.AgentFlowSupport;
import io.github.lnyocly.ai4j.agentflow.trace.AgentFlowTraceContext;
import io.github.lnyocly.ai4j.service.Configuration;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

public class DifyAgentFlowWorkflowService extends AgentFlowSupport implements AgentFlowWorkflowService {

    public DifyAgentFlowWorkflowService(Configuration configuration, AgentFlowConfig agentFlowConfig) {
        super(configuration, agentFlowConfig);
    }

    @Override
    public AgentFlowWorkflowResponse run(AgentFlowWorkflowRequest request) throws Exception {
        AgentFlowTraceContext traceContext = startTrace("workflow", false, request);
        try {
            JSONObject body = buildRequestBody(request, "blocking");
            String url = joinedUrl(requireBaseUrl(), "v1/workflows/run");
            JSONObject response = executeObject(jsonRequestBuilder(url).post(jsonBody(body)).build());
            AgentFlowWorkflowResponse workflowResponse = mapWorkflowResponse(response);
            traceComplete(traceContext, workflowResponse);
            return workflowResponse;
        } catch (Exception ex) {
            traceError(traceContext, ex);
            throw ex;
        }
    }

    @Override
    public void runStream(AgentFlowWorkflowRequest request, final AgentFlowWorkflowListener listener) throws Exception {
        if (listener == null) {
            throw new IllegalArgumentException("listener is required");
        }
        final AgentFlowTraceContext traceContext = startTrace("workflow", true, request);

        JSONObject body = buildRequestBody(request, "streaming");
        String url = joinedUrl(requireBaseUrl(), "v1/workflows/run");
        Request httpRequest = jsonRequestBuilder(url).post(jsonBody(body)).build();

        final CountDownLatch latch = new CountDownLatch(1);
        final AtomicReference<Throwable> failure = new AtomicReference<Throwable>();
        final AtomicReference<AgentFlowWorkflowResponse> completion = new AtomicReference<AgentFlowWorkflowResponse>();
        final AtomicReference<String> taskIdRef = new AtomicReference<String>();
        final AtomicReference<String> workflowRunIdRef = new AtomicReference<String>();
        final AtomicReference<AgentFlowUsage> usageRef = new AtomicReference<AgentFlowUsage>();
        final AtomicReference<Map<String, Object>> outputsRef = new AtomicReference<Map<String, Object>>(Collections.<String, Object>emptyMap());
        final StringBuilder content = new StringBuilder();
        final AtomicBoolean closed = new AtomicBoolean(false);

        eventSourceFactory.newEventSource(httpRequest, new EventSourceListener() {
            @Override
            public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) {
                listener.onOpen();
            }

            @Override
            public void onEvent(@NotNull EventSource eventSource,
                                @Nullable String id,
                                @Nullable String type,
                                @NotNull String data) {
                try {
                    JSONObject payload = parseObjectOrNull(data);
                    String eventType = firstNonBlank(type, payload == null ? null : payload.getString("event"));
                    if (isBlank(eventType) || "ping".equals(eventType)) {
                        return;
                    }

                    if (payload != null) {
                        taskIdRef.set(firstNonBlank(payload.getString("task_id"), taskIdRef.get()));
                        workflowRunIdRef.set(firstNonBlank(payload.getString("workflow_run_id"), workflowRunIdRef.get()));
                    }

                    String outputText = null;
                    String status = null;
                    Map<String, Object> outputs = outputsRef.get();
                    boolean done = false;

                    if ("workflow_finished".equals(eventType)) {
                        done = true;
                        JSONObject dataObject = payload == null ? null : payload.getJSONObject("data");
                        status = dataObject == null ? null : dataObject.getString("status");
                        JSONObject outputObject = dataObject == null ? null : dataObject.getJSONObject("outputs");
                        outputs = outputObject == null
                                ? Collections.<String, Object>emptyMap()
                                : new LinkedHashMap<String, Object>(outputObject);
                        outputsRef.set(outputs);
                        outputText = extractText(outputObject);
                        if (!isBlank(outputText)) {
                            content.setLength(0);
                            content.append(outputText);
                        }
                        AgentFlowUsage usage = usageFromDify(dataObject == null ? null : dataObject.getJSONObject("usage"));
                        if (usage != null) {
                            usageRef.set(usage);
                        }
                    } else if ("message".equals(eventType) || "text_chunk".equals(eventType)) {
                        outputText = payload == null ? null : firstNonBlank(payload.getString("answer"), payload.getString("text"));
                        if (!isBlank(outputText)) {
                            content.append(outputText);
                        }
                    } else if ("error".equals(eventType)) {
                        throw new AgentFlowException("Dify workflow stream error: " + (payload == null ? data : payload.toJSONString()));
                    }

                    AgentFlowWorkflowEvent event = AgentFlowWorkflowEvent.builder()
                            .type(eventType)
                            .status(status)
                            .outputText(outputText)
                            .outputs(outputs)
                            .taskId(taskIdRef.get())
                            .workflowRunId(workflowRunIdRef.get())
                            .done(done)
                            .usage(usageRef.get())
                            .raw(payload == null ? data : payload)
                            .build();
                    listener.onEvent(event);
                    traceEvent(traceContext, event);

                    if (done) {
                        AgentFlowWorkflowResponse responsePayload = AgentFlowWorkflowResponse.builder()
                                .status(status)
                                .outputText(content.toString())
                                .outputs(outputsRef.get())
                                .taskId(taskIdRef.get())
                                .workflowRunId(workflowRunIdRef.get())
                                .usage(usageRef.get())
                                .raw(payload)
                                .build();
                        completion.set(responsePayload);
                        listener.onComplete(responsePayload);
                        traceComplete(traceContext, responsePayload);
                        closed.set(true);
                        eventSource.cancel();
                        latch.countDown();
                    }
                } catch (Throwable ex) {
                    failure.set(ex);
                    traceError(traceContext, ex);
                    listener.onError(ex);
                    closed.set(true);
                    eventSource.cancel();
                    latch.countDown();
                }
            }

            @Override
            public void onClosed(@NotNull EventSource eventSource) {
                if (closed.compareAndSet(false, true)) {
                    AgentFlowWorkflowResponse responsePayload = completion.get();
                    if (responsePayload == null) {
                        responsePayload = AgentFlowWorkflowResponse.builder()
                                .outputText(content.toString())
                                .outputs(outputsRef.get())
                                .taskId(taskIdRef.get())
                                .workflowRunId(workflowRunIdRef.get())
                                .usage(usageRef.get())
                                .build();
                        completion.set(responsePayload);
                        listener.onComplete(responsePayload);
                        traceComplete(traceContext, responsePayload);
                    }
                    latch.countDown();
                }
            }

            @Override
            public void onFailure(@NotNull EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
                Throwable error = t;
                if (error == null && response != null) {
                    error = new AgentFlowException("Dify workflow stream failed: HTTP " + response.code());
                }
                if (error == null) {
                    error = new AgentFlowException("Dify workflow stream failed");
                }
                failure.set(error);
                traceError(traceContext, error);
                listener.onError(error);
                closed.set(true);
                latch.countDown();
            }
        });

        if (!latch.await(pollTimeoutMillis(), TimeUnit.MILLISECONDS)) {
            throw new AgentFlowException("Dify workflow stream timed out");
        }
        if (failure.get() != null) {
            if (failure.get() instanceof Exception) {
                throw (Exception) failure.get();
            }
            throw new AgentFlowException("Dify workflow stream failed", failure.get());
        }
    }

    private JSONObject buildRequestBody(AgentFlowWorkflowRequest request, String responseMode) {
        JSONObject body = new JSONObject();
        body.put("inputs", request.getInputs() == null ? Collections.emptyMap() : request.getInputs());
        body.put("user", defaultUserId(request.getUserId()));
        body.put("response_mode", responseMode);
        if (request.getExtraBody() != null && !request.getExtraBody().isEmpty()) {
            body.putAll(request.getExtraBody());
        }
        return body;
    }

    private AgentFlowWorkflowResponse mapWorkflowResponse(JSONObject response) {
        JSONObject data = response.getJSONObject("data");
        JSONObject outputs = data == null ? null : data.getJSONObject("outputs");
        Map<String, Object> outputMap = outputs == null
                ? Collections.<String, Object>emptyMap()
                : new LinkedHashMap<String, Object>(outputs);
        return AgentFlowWorkflowResponse.builder()
                .status(data == null ? null : data.getString("status"))
                .outputText(extractText(outputs))
                .outputs(outputMap)
                .taskId(response.getString("task_id"))
                .workflowRunId(firstNonBlank(response.getString("workflow_run_id"), data == null ? null : data.getString("id")))
                .usage(usageFromDify(data == null ? null : data.getJSONObject("usage")))
                .raw(response)
                .build();
    }

    private JSONObject parseObjectOrNull(String data) {
        if (isBlank(data)) {
            return null;
        }
        try {
            Object parsed = JSON.parse(data);
            return parsed instanceof JSONObject ? (JSONObject) parsed : null;
        } catch (Exception ex) {
            return null;
        }
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/N8nAgentFlowWorkflowService.java
================================================
package io.github.lnyocly.ai4j.agentflow.workflow;

import io.github.lnyocly.ai4j.agentflow.AgentFlowConfig;
import io.github.lnyocly.ai4j.agentflow.support.AgentFlowSupport;
import io.github.lnyocly.ai4j.agentflow.trace.AgentFlowTraceContext;
import io.github.lnyocly.ai4j.service.Configuration;
import okhttp3.Request;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

public class N8nAgentFlowWorkflowService extends AgentFlowSupport implements AgentFlowWorkflowService {

    public N8nAgentFlowWorkflowService(Configuration configuration, AgentFlowConfig agentFlowConfig) {
        super(configuration, agentFlowConfig);
    }

    @Override
    @SuppressWarnings("unchecked")
    public AgentFlowWorkflowResponse run(AgentFlowWorkflowRequest request) throws Exception {
        AgentFlowTraceContext traceContext = startTrace("workflow", false, request);
        try {
            Map<String, Object> payload = new LinkedHashMap<String, Object>();
            if (request.getInputs() != null) {
                payload.putAll(request.getInputs());
            }
            if (request.getMetadata() != null && !request.getMetadata().isEmpty()) {
                payload.put("_metadata", request.getMetadata());
            }
            if (request.getExtraBody() != null && !request.getExtraBody().isEmpty()) {
                payload.putAll(request.getExtraBody());
            }

            Request httpRequest = jsonRequestBuilder(requireWebhookUrl()).post(jsonBody(payload)).build();
            String responseBody = execute(httpRequest);
            Object raw = parseJsonOrText(responseBody);
            Map<String, Object> outputs = raw instanceof Map
                    ? new LinkedHashMap<String, Object>((Map<String, Object>) raw)
                    : Collections.<String, Object>emptyMap();

            AgentFlowWorkflowResponse workflowResponse = AgentFlowWorkflowResponse.builder()
                    .status("completed")
                    .outputText(extractText(raw))
                    .outputs(outputs)
                    .raw(raw)
                    .build();
            traceComplete(traceContext, workflowResponse);
            return workflowResponse;
        } catch (Exception ex) {
            traceError(traceContext, ex);
            throw ex;
        }
    }

    @Override
    public void runStream(AgentFlowWorkflowRequest request, AgentFlowWorkflowListener listener) {
        throw new UnsupportedOperationException("n8n workflow streaming is not supported yet");
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/annotation/FunctionCall.java
================================================
package io.github.lnyocly.ai4j.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author cly
 * @Description TODO
 * @Date 2024/8/12 15:50
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionCall {
    String name();
    String description();
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/annotation/FunctionParameter.java
================================================
package io.github.lnyocly.ai4j.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author cly
 * @Description TODO
 * @Date 2024/8/12 15:55
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FunctionParameter {
    String description();
    boolean required() default true;
}

================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/annotation/FunctionRequest.java
================================================
package io.github.lnyocly.ai4j.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author cly
 * @Description TODO
 * @Date 2024/8/12 15:55
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionRequest {
    String description() default "";
}

================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/auth/BearerTokenUtils.java
================================================
package io.github.lnyocly.ai4j.auth;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;


public class BearerTokenUtils {
    // 过期时间;默认24小时
    private static final long EXPIRE_MILLIS = 24 * 60 * 60 * 1000L;

    // 缓存服务
    public static Cache<String, String> cache = CacheBuilder.newBuilder()
            .initialCapacity(100)
            .expireAfterWrite(EXPIRE_MILLIS - (60 * 1000L), TimeUnit.MILLISECONDS)
            .build();

    /**
     * 对 API Key 进行签名
     * 新版机制中平台颁发的 API Key 同时包含 “用户标识 id” 和 “签名密钥 secret”,即格式为 {id}.{secret}
     *
     * @param apiKey 智谱APIkey
     * @return Token
     */
    public static String getToken(String apiKey) {
        // 分割APIKEY
        String[] args = apiKey.split("\\.");
        if (args.length != 2) {
            throw new IllegalArgumentException("API Key 格式错误");
        }
        String id = args[0];
        String secret = args[1];
        // 缓存Token
        String token = cache.getIfPresent(apiKey);
        if (null != token) return token;
        // 创建Token
        Algorithm algorithm = Algorithm.HMAC256(secret.getBytes(StandardCharsets.UTF_8));
        Map<String, Object> payload = new HashMap<>();
        payload.put("api_key", id);
        payload.put("exp", System.currentTimeMillis() + EXPIRE_MILLIS);
        payload.put("timestamp", System.currentTimeMillis());
        Map<String, Object> headerClaims = new HashMap<>();
        headerClaims.put("alg", "HS256");
        headerClaims.put("sign_type", "SIGN");
        token = JWT.create().withPayload(payload).withHeader(headerClaims).sign(algorithm);
        cache.put(id, token);
        return token;
    }

    /**
     * apiKey 属于SecretId与SecretKey的拼接,格式为 {SecretId}.{SecretKey}
     *
     * @param apiKey 腾讯混元APIkey
     * @return
     */
    public static String getAuthorization(String apiKey, String action, String payloadJson) throws Exception {
        String[] args = apiKey.split("\\.");
        if (args.length != 2) {
            throw new IllegalArgumentException("API Key 格式错误");
        }
        String id = args[0];
        String key = args[1];

        String algorithm = "TC3-HMAC-SHA256";
        String service = "hunyuan";
        String host = "hunyuan.tencentcloudapi.com";
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 注意时区,否则容易出错
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));

        // ************* 步骤 1:拼接规范请求串 *************
        String httpRequestMethod = "POST";
        String canonicalUri = "/";
        String canonicalQueryString = "";
        String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n" + "x-tc-action:" + action.toLowerCase() + "\n";
        String signedHeaders = "content-type;host;x-tc-action";
        String hashedRequestPayload = sha256Hex(payloadJson);

        String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
                + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;

        // ************* 步骤 2:拼接待签名字符串 *************
        String credentialScope = date + "/" + service + "/" + "tc3_request";
        String hashedCanonicalRequest = sha256Hex(canonicalRequest);

        String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;

        // ************* 步骤 3:计算签名 *************
        byte[] secretDate = hmac256(("TC3" + key).getBytes(StandardCharsets.UTF_8), date);
        byte[] secretService = hmac256(secretDate, service);
        byte[] secretSigning = hmac256(secretService, "tc3_request");

        String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();

        // ************* 步骤 4:拼接 Authorization *************
        String authorization = algorithm + " " + "Credential=" + id + "/" + credentialScope + ", "
                + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
        return authorization;
    }

    private static byte[] hmac256(byte[] key, String msg) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
        mac.init(secretKeySpec);
        return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
    }

    private static String sha256Hex(String s) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] d = md.digest(s.getBytes(StandardCharsets.UTF_8));
        return DatatypeConverter.printHexBinary(d).toLowerCase();
    }

}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/AiPlatform.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.Data;

@Data
public class AiPlatform {
    private String id;
    private String platform;
    private String apiHost;
    private String apiKey;
    private String chatCompletionUrl;
    private String embeddingUrl;
    private String speechUrl;
    private String transcriptionUrl;
    private String translationUrl;
    private String realtimeUrl;
    private String rerankApiHost;
    private String rerankUrl;
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/BaichuanConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class BaichuanConfig {

    private String apiHost = "https://api.baichuan-ai.com/";
    private String apiKey = "";
    private String chatCompletionUrl = "v1/chat/completions";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/DashScopeConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author cly
 * @Description OpenAi骞冲彴閰嶇疆鏂囦欢淇℃伅
 * @Date 2024/8/8 0:18
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DashScopeConfig {
    private String apiHost = "https://dashscope.aliyuncs.com/api/v2/apps/protocols/compatible-mode/v1/";
    private String responsesUrl = "responses";
    private String apiKey = "";
}



================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/DeepSeekConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author cly
 * @Description DeepSeek 配置文件
 * @Date 2024/8/29 10:31
 */

@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeepSeekConfig {

    private String apiHost = "https://api.deepseek.com/";
    private String apiKey = "";
    private String chatCompletionUrl = "chat/completions";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/DoubaoConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author cly
 * @Description 璞嗗寘(鐏北寮曟搸鏂硅垷) 閰嶇疆鏂囦欢
 */

@Data
@NoArgsConstructor
@AllArgsConstructor
public class DoubaoConfig {

    private String apiHost = "https://ark.cn-beijing.volces.com/api/v3/";
    private String apiKey = "";
    private String chatCompletionUrl = "chat/completions";
    private String imageGenerationUrl = "images/generations";
    private String responsesUrl = "responses";
    private String rerankApiHost = "https://api-knowledgebase.mlp.cn-beijing.volces.com/";
    private String rerankUrl = "api/knowledge/service/rerank";
}



================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/HunyuanConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author cly
 * @Description 腾讯混元配置
 * @Date 2024/8/30 19:50
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HunyuanConfig {
    private String apiHost = "https://hunyuan.tencentcloudapi.com/";
    /**
     * apiKey 属于SecretId与SecretKey的拼接,格式为 {SecretId}.{SecretKey}
     */
    private String apiKey = "";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/JinaConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class JinaConfig {

    private String apiHost = "https://api.jina.ai/";

    private String apiKey = "";

    private String rerankUrl = "v1/rerank";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/LingyiConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author cly
 * @Description 零一万物大模型
 * @Date 2024/9/9 22:53
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LingyiConfig {
    private String apiHost = "https://api.lingyiwanwu.com/";
    private String apiKey = "";
    private String chatCompletionUrl = "v1/chat/completions";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/McpConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.Data;

/**
 * @Author cly
 * @Description MCP (Model Context Protocol) 配置类
 */
@Data
public class McpConfig {
    
    /**
     * MCP服务器地址
     */
    private String serverUrl;
    
    /**
     * MCP服务器端口
     */
    private Integer serverPort = 3000;
    
    /**
     * 连接超时时间(毫秒)
     */
    private Long connectTimeout = 30000L;
    
    /**
     * 读取超时时间(毫秒)
     */
    private Long readTimeout = 60000L;
    
    /**
     * 写入超时时间(毫秒)
     */
    private Long writeTimeout = 60000L;
    
    /**
     * 是否启用SSL
     */
    private Boolean enableSsl = false;
    
    /**
     * 认证令牌
     */
    private String authToken;
    
    /**
     * 客户端名称
     */
    private String clientName = "ai4j-mcp-client";
    
    /**
     * 客户端版本
     */
    private String clientVersion = "1.0.0";
    
    /**
     * 最大重连次数
     */
    private Integer maxRetries = 3;
    
    /**
     * 重连间隔(毫秒)
     */
    private Long retryInterval = 5000L;
    
    /**
     * 是否启用心跳检测
     */
    private Boolean enableHeartbeat = true;
    
    /**
     * 心跳间隔(毫秒)
     */
    private Long heartbeatInterval = 30000L;
    
    /**
     * 消息队列大小
     */
    private Integer messageQueueSize = 1000;
    
    /**
     * 是否启用消息压缩
     */
    private Boolean enableCompression = false;
    
    /**
     * 传输类型:stdio, http, websocket
     */
    private String transportType = "http";
    
    /**
     * 获取完整的服务器URL
     */
    public String getFullServerUrl() {
        if (serverUrl == null) {
            return null;
        }
        
        String protocol = enableSsl ? "https" : "http";
        if (serverUrl.startsWith("http://") || serverUrl.startsWith("https://")) {
            return serverUrl;
        }
        
        return String.format("%s://%s:%d", protocol, serverUrl, serverPort);
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/MilvusConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Arrays;
import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MilvusConfig {

    private boolean enabled = false;

    private String host = "http://localhost:19530";

    private String token = "";

    private String dbName = "";

    private String partitionName = "";

    private String idField = "id";

    private String vectorField = "vector";

    private String contentField = "content";

    private List<String> outputFields = Arrays.asList(
            "id",
            "content",
            "documentId",
            "sourceName",
            "sourcePath",
            "sourceUri",
            "pageNumber",
            "sectionTitle",
            "chunkIndex"
    );

    private String upsert = "/v2/vectordb/entities/upsert";

    private String search = "/v2/vectordb/entities/search";

    private String delete = "/v2/vectordb/entities/delete";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/MinimaxConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author : isxuwl
 * @Date: 2024/10/15 16:08
 * @Model Description:
 * @Description:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MinimaxConfig {
    private String apiHost = "https://api.minimax.chat/";
    private String apiKey = "";
    private String chatCompletionUrl = "v1/text/chatcompletion_v2";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/MoonshotConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author cly
 * @Description 月之暗面配置
 * @Date 2024/8/29 23:00
 */

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MoonshotConfig {
    private String apiHost = "https://api.moonshot.cn/";
    private String apiKey = "";
    private String chatCompletionUrl = "v1/chat/completions";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/OkHttpConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import okhttp3.logging.HttpLoggingInterceptor;

/**
 * @Author cly
 * @Description OkHttp配置信息
 * @Date 2024/8/11 0:11
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OkHttpConfig {

    private HttpLoggingInterceptor.Level log = HttpLoggingInterceptor.Level.HEADERS;
    private int connectTimeout = 300;
    private int writeTimeout = 300;
    private int readTimeout = 300;
    private int proxyPort = 10809;
    private String proxyHost = "";


}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/OllamaConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author cly
 * @Description Ollama配置文件
 * @Date 2024/9/20 11:07
 */

@Data
@NoArgsConstructor
@AllArgsConstructor
public class OllamaConfig {
    private String apiHost = "http://localhost:11434/";
    private String apiKey = "";
    private String chatCompletionUrl = "api/chat";
    private String embeddingUrl = "api/embed";
    private String rerankUrl = "api/rerank";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/OpenAiConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author cly
 * @Description OpenAi骞冲彴閰嶇疆鏂囦欢淇℃伅
 * @Date 2024/8/8 0:18
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OpenAiConfig {
    private String apiHost = "https://api.openai.com/";
    private String apiKey = "";
    private String chatCompletionUrl = "v1/chat/completions";
    private String embeddingUrl = "v1/embeddings";
    private String speechUrl = "v1/audio/speech";
    private String transcriptionUrl = "v1/audio/transcriptions";
    private String translationUrl = "v1/audio/translations";
    private String realtimeUrl = "v1/realtime";
    private String imageGenerationUrl = "v1/images/generations";
    private String responsesUrl = "v1/responses";

}



================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/PgVectorConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PgVectorConfig {

    private boolean enabled = false;

    private String jdbcUrl = "jdbc:postgresql://localhost:5432/postgres";

    private String username = "";

    private String password = "";

    private String tableName = "ai4j_vectors";

    private String idColumn = "id";

    private String datasetColumn = "dataset";

    private String vectorColumn = "embedding";

    private String contentColumn = "content";

    private String metadataColumn = "metadata";

    private String distanceOperator = "<=>";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/PineconeConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author cly
 * @Description Pinecone向量数据配置文件
 * @Date 2024/8/16 16:37
 */

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PineconeConfig {
    private String host = "https://xxx.svc.xxx.pinecone.io";
    private String key = "";

    private String upsert = "/vectors/upsert";
    private String query = "/query";
    private String delete = "/vectors/delete";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/QdrantConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class QdrantConfig {

    private boolean enabled = false;

    private String host = "http://localhost:6333";

    private String apiKey = "";

    private String vectorName = "";

    private String upsert = "/collections/%s/points";

    private String query = "/collections/%s/points/query";

    private String delete = "/collections/%s/points/delete";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/config/ZhipuConfig.java
================================================
package io.github.lnyocly.ai4j.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author cly
 * @Description 智谱AI平台配置信息
 * @Date 2024/8/27 22:12
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ZhipuConfig {

    private String apiHost = "https://open.bigmodel.cn/api/paas/";
    private String apiKey = "";
    private String chatCompletionUrl = "v4/chat/completions";
    private String embeddingUrl= "v4/embeddings";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/constant/Constants.java
================================================
package io.github.lnyocly.ai4j.constant;

/**
 * @Author cly
 * @Description TODO
 * @Date 2024/8/11 0:19
 */
public class Constants {
    public static final String SSE_CONTENT_TYPE = "text/event-stream";
    public static final String DEFAULT_USER_AGENT = "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)";
    public static final String APPLICATION_JSON = "application/json";
    public static final String JSON_CONTENT_TYPE = APPLICATION_JSON + "; charset=utf-8";
    public static final String METADATA_KEY = "content";
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/convert/audio/AudioParameterConvert.java
================================================
package io.github.lnyocly.ai4j.convert.audio;

/**
 * @Author cly
 * @Description 处理请求参数。 由统一的OpenAi音频格式--->其它模型格式
 * @Date 2024/10/12 13:36
 */
public interface AudioParameterConvert<T> {
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/convert/audio/AudioResultConvert.java
================================================
package io.github.lnyocly.ai4j.convert.audio;

/**
 * @Author cly
 * @Description 返回结果统一处理。 其它模型音频返回格式--->统一的OpenAi返回格式
 * @Date 2024/10/12 13:35
 */
public interface AudioResultConvert<T> {
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/convert/chat/ParameterConvert.java
================================================
package io.github.lnyocly.ai4j.convert.chat;

import io.github.lnyocly.ai4j.platform.openai.chat.entity.ChatCompletion;

/**
 * @Author cly
 * @Description 处理请求参数 统一的OpenAi格式--->其它模型格式
 * @Date 2024/8/12 1:04
 */
public interface ParameterConvert<T> {
    T convertChatCompletionObject(ChatCompletion chatCompletion);
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/convert/chat/ResultConvert.java
================================================
package io.github.lnyocly.ai4j.convert.chat;

import io.github.lnyocly.ai4j.listener.SseListener;
import io.github.lnyocly.ai4j.platform.openai.chat.entity.ChatCompletionResponse;
import okhttp3.sse.EventSourceListener;

/**
 * @Author cly
 * @Description 处理结果输出 其它模型格式--->统一的OpenAi格式
 * @Date 2024/8/12 1:05
 */
public interface ResultConvert<T> {
    EventSourceListener convertEventSource(SseListener eventSourceListener);
    ChatCompletionResponse convertChatCompletionResponse(T t);
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/convert/embedding/EmbeddingParameterConvert.java
================================================
package io.github.lnyocly.ai4j.convert.embedding;


import io.github.lnyocly.ai4j.platform.openai.embedding.entity.Embedding;

/**
 * EmbeddingParameterConvert
 * @param <T>
 */
public interface EmbeddingParameterConvert<T> {
    T convertEmbeddingRequest(Embedding embeddingRequest);
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/convert/embedding/EmbeddingResultConvert.java
================================================
package io.github.lnyocly.ai4j.convert.embedding;

import io.github.lnyocly.ai4j.platform.openai.embedding.entity.EmbeddingResponse;


/**
 * @Author cly
 * @param <T>
 */
public interface EmbeddingResultConvert<T> {
    EmbeddingResponse convertEmbeddingResponse(T t);
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/document/RecursiveCharacterTextSplitter.java
================================================
package io.github.lnyocly.ai4j.document;

import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Author cly
 * @Description 分词器
 * @Date 2024/8/2 22:59
 */
@Slf4j
public class RecursiveCharacterTextSplitter {
    private List<String> separators;
    private int chunkSize = 500;
    private int chunkOverlap = 50;

    // 构造函数,接受分隔符列表、块大小和块重叠作为参数
    public RecursiveCharacterTextSplitter(List<String> separators, int chunkSize, int chunkOverlap) {
        // 如果分隔符列表为null,则使用默认值
        if (separators == null) {
            this.separators = Arrays.asList("\n\n", "\n", " ", "");
        } else {
            this.separators = separators;
        }
        this.chunkSize = chunkSize;
        this.chunkOverlap = chunkOverlap;
    }

    public RecursiveCharacterTextSplitter(int chunkSize, int chunkOverlap) {
        this.separators = Arrays.asList("\n\n", "\n", " ", "");
        this.chunkSize = chunkSize;
        this.chunkOverlap = chunkOverlap;
    }

    // 将文本分割成块的方法
    public List<String> splitText(String text) {
        // 声明一个空的字符串列表,用于存储最终的文本块
        List<String> finalChunks = new ArrayList<>();
        String separator = separators.get(separators.size() - 1);

        // 循环遍历分隔符列表,找到可以在文本中找到的最合适的分隔符
        for (String s : separators) {
            if (text.contains(s) || s.isEmpty()) {
                separator = s;
                break;
            }
        }

        List<String> splits = Arrays.asList(text.split(separator));

        // 声明一个空的字符串列表,用于存储长度小于块大小的子字符串
        List<String> goodSplits = new ArrayList<>();
        // 循环遍历子字符串列表,将较短的子字符串添加到goodSplits列表中,将较长的子字符串递归地传递给splitText方法
        for (String s : splits) {
            if (s.length() < chunkSize) {
                goodSplits.add(s);
            } else {
                if (!goodSplits.isEmpty()) {
                    // 将goodSplits列表中的子字符串合并为一个文本块,并将其添加到最终的文本块列表中
                    List<String> mergedText = mergeSplits(goodSplits, separator);
                    finalChunks.addAll(mergedText);
                    goodSplits.clear();
                }
                // 递归地将较长的子字符串传递给splitText方法
                List<String> otherInfo = splitText(s);
                finalChunks.addAll(otherInfo);
            }
        }

        if (!goodSplits.isEmpty()) {
            List<String> mergedText = mergeSplits(goodSplits, separator);
            finalChunks.addAll(mergedText);
        }

        return finalChunks;
    }

    private List<String> mergeSplits(List<String> splits, String separator) {
        int separatorLen = separator.length();

        List<String> docs = new ArrayList<>();
        List<String> currentDoc = new ArrayList<>();
        int total = 0;

        for (String d : splits) {
            int len = d.length();
            if (total + len + (separatorLen > 0 && !currentDoc.isEmpty() ? separatorLen : 0) > chunkSize) {
                if (total > chunkSize) {
                    log.warn("Warning: Created a chunk of size {}, which is longer than the specified {}", total, chunkSize);
                }
                if (!currentDoc.isEmpty()) {
                    String doc = joinDocs(currentDoc, separator);
                    if (doc != null) {
                        docs.add(doc);
                    }
                    // 通过移除currentDoc中的文档,将currentDoc的长度减小到指定的文档重叠长度chunkOverlap或更小, 结果存到下一个chunk的开始位置
                    while (total > chunkOverlap || (total + len + (separatorLen > 0 && !currentDoc.isEmpty() ? separatorLen : 0) > chunkSize && total > 0)) {
                        total -= currentDoc.get(0).length() + (separatorLen > 0 && currentDoc.size() > 1 ? separatorLen : 0);
                        currentDoc.remove(0);
                    }
                }
            }
            currentDoc.add(d);
            total += len + (separatorLen > 0 && currentDoc.size() > 1 ? separatorLen : 0);
        }

        String doc = joinDocs(currentDoc, separator);
        if (doc != null) {
            docs.add(doc);
        }

        return docs;
    }

    private String joinDocs(List<String> docs, String separator) {
        if (docs.isEmpty()) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < docs.size(); i++) {
            sb.append(docs.get(i));
            if (i < docs.size() - 1) {
                sb.append(separator);
            }
        }
        return sb.toString();
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/document/TikaUtil.java
================================================
package io.github.lnyocly.ai4j.document;

import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.SAXException;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public class TikaUtil {

    private static final Tika tika = new Tika();

    /**
     * 解析File文件,返回文档内容
     * @param file 要解析的文件
     * @return 解析后的文档内容
     * @throws IOException
     * @throws TikaException
     * @throws SAXException
     */
    public static String parseFile(File file) throws IOException, TikaException, SAXException {
        try (InputStream stream = file.toURI().toURL().openStream()) {
            return parseInputStream(stream);
        }
    }

    /**
     * 解析InputStream输入流,返回文档内容
     * @param stream 要解析的输入流
     * @return 解析后的文档内容
     * @throws IOException
     * @throws TikaException
     * @throws SAXException
     */
    public static String parseInputStream(InputStream stream) throws IOException, TikaException, SAXException {
        BodyContentHandler handler = new BodyContentHandler();
        Metadata metadata = new Metadata();
        AutoDetectParser parser = new AutoDetectParser();
        ParseContext context = new ParseContext();

        parser.parse(stream, handler, metadata, context);
        return handler.toString();
    }

    /**
     * 使用Tika简单接口解析文件,返回文档内容
     * @param file 要解析的文件
     * @return 解析后的文档内容
     * @throws IOException
     * @throws TikaException
     */
    public static String parseFileWithTika(File file) throws IOException, TikaException {
        return tika.parseToString(file);
    }

    /**
     * 解析InputStream输入流,使用Tika简单接口,返回文档内容
     * @param stream 要解析的输入流
     * @return 解析后的文档内容
     * @throws IOException
     * @throws TikaException
     */
    public static String parseInputStreamWithTika(InputStream stream) throws IOException, TikaException {
        return tika.parseToString(stream);
    }

    /**
     * 检测File文件的MIME类型
     * @param file 要检测的文件
     * @return MIME类型
     * @throws IOException
     */
    public static String detectMimeType(File file) throws IOException {
        return tika.detect(file);
    }

    /**
     * 检测InputStream输入流的MIME类型
     * @param stream 要检测的输入流
     * @return MIME类型
     * @throws IOException
     */
    public static String detectMimeType(InputStream stream) throws IOException {
        return tika.detect(stream);
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/exception/Ai4jException.java
================================================
package io.github.lnyocly.ai4j.exception;

/**
 * Base runtime exception for ai4j shared abstractions.
 */
public class Ai4jException extends RuntimeException {

    public Ai4jException(String message) {
        super(message);
    }

    public Ai4jException(String message, Throwable cause) {
        super(message, cause);
    }
}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/exception/CommonException.java
================================================
package io.github.lnyocly.ai4j.exception;

/**
 * Legacy exception kept for 1.x compatibility.
 */
public class CommonException extends Ai4jException {

    public CommonException(String msg) {
        super(msg);
    }
}



================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/exception/chain/AbstractErrorHandler.java
================================================
package io.github.lnyocly.ai4j.exception.chain;

import io.github.lnyocly.ai4j.exception.error.Error;
import io.github.lnyocly.ai4j.exception.error.OpenAiError;

/**
 * @Author cly
 * @Description 错误处理抽象
 * @Date 2024/9/18 20:57
 */
public abstract class AbstractErrorHandler implements IErrorHandler{
    protected IErrorHandler nextHandler;

    @Override
    public void setNext(IErrorHandler handler) {
        this.nextHandler = handler;
    }

    protected Error handleNext(String errorInfo) {
        if (nextHandler != null) {
            return nextHandler.parseError(errorInfo);
        }
        return null;
    }

}


================================================
FILE: ai4j/src/main/java/io/github/lnyocly/ai4j/exception/chain/ErrorHandler.java
================================================
package io.github.lnyocly.ai4j.exception.chain;

import io.github.lnyocly.ai4j.exception.chain.impl.HunyuanErrorHandler;
import io.github.lnyocly.ai4j.exception.chain.impl.OpenAiErrorHandler;
import io.github.lnyocly.ai4j.exception.chain.impl.UnknownErrorHandler;
import io.github.lnyocly.ai4j.exception.error.Error;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author cly
 * @Description 创建错误处理的单例
 * @Date 2024/9/18 21:09
 */
public class ErrorHandler {
    private List<IErrorHandler> handlers;
    private IErrorHandler chain;

    private ErrorHandler() {
        handlers = new ArrayList<>();
        // 添加错误处理器
        handlers.add(new OpenAiErrorHandler());
        handlers.add(new HunyuanErrorHandler());

        // 兜底的错误处理
        handlers.add(new UnknownErrorHandler());

        // 组装链
        this.assembleChain();
    }

    private void assembleChain(){
        chain = handlers.get(0);
        IErrorHandler curr = handlers.get(0);
        for (int i = 1; i < handlers.size(); i++) {
            curr.setNext(handlers.get(i));
            curr = handlers.get(i);
        }
    }

    private static class ErrorHandlerHolder {
        private static final ErrorHandler INSTANCE = new ErrorHandler();
    }

    public static ErrorHandler getInstance() {
        return ErrorHandlerHolder.INSTANCE;
    }

    public Error process(String errorSring){
        return chain.parseError(er
Download .txt
gitextract_x29x44af/

├── .editorconfig
├── .github/
│   └── workflows/
│       ├── docs-build.yml
│       └── docs-pages.yml
├── .gitignore
├── LICENSE
├── README-EN.md
├── README.md
├── ai4j/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── github/
│       │   │           └── lnyocly/
│       │   │               └── ai4j/
│       │   │                   ├── agentflow/
│       │   │                   │   ├── AgentFlow.java
│       │   │                   │   ├── AgentFlowConfig.java
│       │   │                   │   ├── AgentFlowException.java
│       │   │                   │   ├── AgentFlowType.java
│       │   │                   │   ├── AgentFlowUsage.java
│       │   │                   │   ├── chat/
│       │   │                   │   │   ├── AgentFlowChatEvent.java
│       │   │                   │   │   ├── AgentFlowChatListener.java
│       │   │                   │   │   ├── AgentFlowChatRequest.java
│       │   │                   │   │   ├── AgentFlowChatResponse.java
│       │   │                   │   │   ├── AgentFlowChatService.java
│       │   │                   │   │   ├── CozeAgentFlowChatService.java
│       │   │                   │   │   └── DifyAgentFlowChatService.java
│       │   │                   │   ├── support/
│       │   │                   │   │   └── AgentFlowSupport.java
│       │   │                   │   ├── trace/
│       │   │                   │   │   ├── AgentFlowTraceContext.java
│       │   │                   │   │   └── AgentFlowTraceListener.java
│       │   │                   │   └── workflow/
│       │   │                   │       ├── AgentFlowWorkflowEvent.java
│       │   │                   │       ├── AgentFlowWorkflowListener.java
│       │   │                   │       ├── AgentFlowWorkflowRequest.java
│       │   │                   │       ├── AgentFlowWorkflowResponse.java
│       │   │                   │       ├── AgentFlowWorkflowService.java
│       │   │                   │       ├── CozeAgentFlowWorkflowService.java
│       │   │                   │       ├── DifyAgentFlowWorkflowService.java
│       │   │                   │       └── N8nAgentFlowWorkflowService.java
│       │   │                   ├── annotation/
│       │   │                   │   ├── FunctionCall.java
│       │   │                   │   ├── FunctionParameter.java
│       │   │                   │   └── FunctionRequest.java
│       │   │                   ├── auth/
│       │   │                   │   └── BearerTokenUtils.java
│       │   │                   ├── config/
│       │   │                   │   ├── AiPlatform.java
│       │   │                   │   ├── BaichuanConfig.java
│       │   │                   │   ├── DashScopeConfig.java
│       │   │                   │   ├── DeepSeekConfig.java
│       │   │                   │   ├── DoubaoConfig.java
│       │   │                   │   ├── HunyuanConfig.java
│       │   │                   │   ├── JinaConfig.java
│       │   │                   │   ├── LingyiConfig.java
│       │   │                   │   ├── McpConfig.java
│       │   │                   │   ├── MilvusConfig.java
│       │   │                   │   ├── MinimaxConfig.java
│       │   │                   │   ├── MoonshotConfig.java
│       │   │                   │   ├── OkHttpConfig.java
│       │   │                   │   ├── OllamaConfig.java
│       │   │                   │   ├── OpenAiConfig.java
│       │   │                   │   ├── PgVectorConfig.java
│       │   │                   │   ├── PineconeConfig.java
│       │   │                   │   ├── QdrantConfig.java
│       │   │                   │   └── ZhipuConfig.java
│       │   │                   ├── constant/
│       │   │                   │   └── Constants.java
│       │   │                   ├── convert/
│       │   │                   │   ├── audio/
│       │   │                   │   │   ├── AudioParameterConvert.java
│       │   │                   │   │   └── AudioResultConvert.java
│       │   │                   │   ├── chat/
│       │   │                   │   │   ├── ParameterConvert.java
│       │   │                   │   │   └── ResultConvert.java
│       │   │                   │   └── embedding/
│       │   │                   │       ├── EmbeddingParameterConvert.java
│       │   │                   │       └── EmbeddingResultConvert.java
│       │   │                   ├── document/
│       │   │                   │   ├── RecursiveCharacterTextSplitter.java
│       │   │                   │   └── TikaUtil.java
│       │   │                   ├── exception/
│       │   │                   │   ├── Ai4jException.java
│       │   │                   │   ├── CommonException.java
│       │   │                   │   ├── chain/
│       │   │                   │   │   ├── AbstractErrorHandler.java
│       │   │                   │   │   ├── ErrorHandler.java
│       │   │                   │   │   ├── IErrorHandler.java
│       │   │                   │   │   └── impl/
│       │   │                   │   │       ├── HunyuanErrorHandler.java
│       │   │                   │   │       ├── OpenAiErrorHandler.java
│       │   │                   │   │       └── UnknownErrorHandler.java
│       │   │                   │   └── error/
│       │   │                   │       ├── Error.java
│       │   │                   │       ├── HunyuanError.java
│       │   │                   │       └── OpenAiError.java
│       │   │                   ├── interceptor/
│       │   │                   │   ├── ContentTypeInterceptor.java
│       │   │                   │   └── ErrorInterceptor.java
│       │   │                   ├── listener/
│       │   │                   │   ├── AbstractManagedStreamListener.java
│       │   │                   │   ├── ImageSseListener.java
│       │   │                   │   ├── ManagedStreamListener.java
│       │   │                   │   ├── RealtimeListener.java
│       │   │                   │   ├── ResponseSseListener.java
│       │   │                   │   ├── SseListener.java
│       │   │                   │   ├── StreamExecutionOptions.java
│       │   │                   │   └── StreamExecutionSupport.java
│       │   │                   ├── mcp/
│       │   │                   │   ├── annotation/
│       │   │                   │   │   ├── McpParameter.java
│       │   │                   │   │   ├── McpPrompt.java
│       │   │                   │   │   ├── McpPromptParameter.java
│       │   │                   │   │   ├── McpResource.java
│       │   │                   │   │   ├── McpResourceParameter.java
│       │   │                   │   │   ├── McpService.java
│       │   │                   │   │   └── McpTool.java
│       │   │                   │   ├── client/
│       │   │                   │   │   ├── McpClient.java
│       │   │                   │   │   └── McpClientResponseSupport.java
│       │   │                   │   ├── config/
│       │   │                   │   │   ├── FileMcpConfigSource.java
│       │   │                   │   │   ├── McpConfigIO.java
│       │   │                   │   │   ├── McpConfigManager.java
│       │   │                   │   │   ├── McpConfigSource.java
│       │   │                   │   │   └── McpServerConfig.java
│       │   │                   │   ├── entity/
│       │   │                   │   │   ├── McpError.java
│       │   │                   │   │   ├── McpInitializeResponse.java
│       │   │                   │   │   ├── McpMessage.java
│       │   │                   │   │   ├── McpNotification.java
│       │   │                   │   │   ├── McpPrompt.java
│       │   │                   │   │   ├── McpPromptResult.java
│       │   │                   │   │   ├── McpRequest.java
│       │   │                   │   │   ├── McpResource.java
│       │   │                   │   │   ├── McpResourceContent.java
│       │   │                   │   │   ├── McpResponse.java
│       │   │                   │   │   ├── McpRoot.java
│       │   │                   │   │   ├── McpSamplingRequest.java
│       │   │                   │   │   ├── McpSamplingResult.java
│       │   │                   │   │   ├── McpServerInfo.java
│       │   │                   │   │   ├── McpServerReference.java
│       │   │                   │   │   ├── McpTool.java
│       │   │                   │   │   ├── McpToolDefinition.java
│       │   │                   │   │   └── McpToolResult.java
│       │   │                   │   ├── gateway/
│       │   │                   │   │   ├── McpGateway.java
│       │   │                   │   │   ├── McpGatewayClientFactory.java
│       │   │                   │   │   ├── McpGatewayConfigSourceBinding.java
│       │   │                   │   │   ├── McpGatewayKeySupport.java
│       │   │                   │   │   └── McpGatewayToolRegistry.java
│       │   │                   │   ├── server/
│       │   │                   │   │   ├── McpHttpServerSupport.java
│       │   │                   │   │   ├── McpServer.java
│       │   │                   │   │   ├── McpServerEngine.java
│       │   │                   │   │   ├── McpServerFactory.java
│       │   │                   │   │   ├── McpServerSessionState.java
│       │   │                   │   │   ├── McpServerSessionSupport.java
│       │   │                   │   │   ├── SseMcpServer.java
│       │   │                   │   │   ├── StdioMcpServer.java
│       │   │                   │   │   └── StreamableHttpMcpServer.java
│       │   │                   │   ├── transport/
│       │   │                   │   │   ├── McpTransport.java
│       │   │                   │   │   ├── McpTransportFactory.java
│       │   │                   │   │   ├── McpTransportSupport.java
│       │   │                   │   │   ├── SseTransport.java
│       │   │                   │   │   ├── StdioTransport.java
│       │   │                   │   │   ├── StreamableHttpTransport.java
│       │   │                   │   │   └── TransportConfig.java
│       │   │                   │   └── util/
│       │   │                   │       ├── McpMessageCodec.java
│       │   │                   │       ├── McpPromptAdapter.java
│       │   │                   │       ├── McpResourceAdapter.java
│       │   │                   │       ├── McpToolAdapter.java
│       │   │                   │       ├── McpToolConversionSupport.java
│       │   │                   │       └── McpTypeSupport.java
│       │   │                   ├── memory/
│       │   │                   │   ├── ChatMemory.java
│       │   │                   │   ├── ChatMemoryItem.java
│       │   │                   │   ├── ChatMemoryPolicy.java
│       │   │                   │   ├── ChatMemorySnapshot.java
│       │   │                   │   ├── ChatMemorySummarizer.java
│       │   │                   │   ├── ChatMemorySummaryRequest.java
│       │   │                   │   ├── InMemoryChatMemory.java
│       │   │                   │   ├── JdbcChatMemory.java
│       │   │                   │   ├── JdbcChatMemoryConfig.java
│       │   │                   │   ├── MessageWindowChatMemoryPolicy.java
│       │   │                   │   ├── SummaryChatMemoryPolicy.java
│       │   │                   │   ├── SummaryChatMemoryPolicyConfig.java
│       │   │                   │   └── UnboundedChatMemoryPolicy.java
│       │   │                   ├── network/
│       │   │                   │   ├── ConnectionPoolProvider.java
│       │   │                   │   ├── DispatcherProvider.java
│       │   │                   │   ├── OkHttpUtil.java
│       │   │                   │   ├── UrlUtils.java
│       │   │                   │   └── impl/
│       │   │                   │       ├── DefaultConnectionPoolProvider.java
│       │   │                   │       └── DefaultDispatcherProvider.java
│       │   │                   ├── platform/
│       │   │                   │   ├── baichuan/
│       │   │                   │   │   └── chat/
│       │   │                   │   │       ├── BaichuanChatService.java
│       │   │                   │   │       └── entity/
│       │   │                   │   │           ├── BaichuanChatCompletion.java
│       │   │                   │   │           └── BaichuanChatCompletionResponse.java
│       │   │                   │   ├── dashscope/
│       │   │                   │   │   ├── DashScopeChatService.java
│       │   │                   │   │   ├── entity/
│       │   │                   │   │   │   └── DashScopeResult.java
│       │   │                   │   │   ├── response/
│       │   │                   │   │   │   └── DashScopeResponsesService.java
│       │   │                   │   │   └── util/
│       │   │                   │   │       └── MessageUtil.java
│       │   │                   │   ├── deepseek/
│       │   │                   │   │   └── chat/
│       │   │                   │   │       ├── DeepSeekChatService.java
│       │   │                   │   │       └── entity/
│       │   │                   │   │           ├── DeepSeekChatCompletion.java
│       │   │                   │   │           └── DeepSeekChatCompletionResponse.java
│       │   │                   │   ├── doubao/
│       │   │                   │   │   ├── chat/
│       │   │                   │   │   │   ├── DoubaoChatService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── DoubaoChatCompletion.java
│       │   │                   │   │   │       └── DoubaoChatCompletionResponse.java
│       │   │                   │   │   ├── image/
│       │   │                   │   │   │   ├── DoubaoImageService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       └── DoubaoImageGenerationRequest.java
│       │   │                   │   │   ├── rerank/
│       │   │                   │   │   │   └── DoubaoRerankService.java
│       │   │                   │   │   └── response/
│       │   │                   │   │       └── DoubaoResponsesService.java
│       │   │                   │   ├── hunyuan/
│       │   │                   │   │   ├── HunyuanConstant.java
│       │   │                   │   │   ├── chat/
│       │   │                   │   │   │   ├── HunyuanChatService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── HunyuanChatCompletion.java
│       │   │                   │   │   │       └── HunyuanChatCompletionResponse.java
│       │   │                   │   │   └── support/
│       │   │                   │   │       └── HunyuanJsonUtil.java
│       │   │                   │   ├── jina/
│       │   │                   │   │   └── rerank/
│       │   │                   │   │       └── JinaRerankService.java
│       │   │                   │   ├── lingyi/
│       │   │                   │   │   └── chat/
│       │   │                   │   │       ├── LingyiChatService.java
│       │   │                   │   │       └── entity/
│       │   │                   │   │           ├── LingyiChatCompletion.java
│       │   │                   │   │           └── LingyiChatCompletionResponse.java
│       │   │                   │   ├── minimax/
│       │   │                   │   │   └── chat/
│       │   │                   │   │       ├── MinimaxChatService.java
│       │   │                   │   │       └── entity/
│       │   │                   │   │           ├── MinimaxChatCompletion.java
│       │   │                   │   │           └── MinimaxChatCompletionResponse.java
│       │   │                   │   ├── moonshot/
│       │   │                   │   │   └── chat/
│       │   │                   │   │       ├── MoonshotChatService.java
│       │   │                   │   │       └── entity/
│       │   │                   │   │           ├── MoonshotChatCompletion.java
│       │   │                   │   │           └── MoonshotChatCompletionResponse.java
│       │   │                   │   ├── ollama/
│       │   │                   │   │   ├── chat/
│       │   │                   │   │   │   ├── OllamaAiChatService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── OllamaChatCompletion.java
│       │   │                   │   │   │       ├── OllamaChatCompletionResponse.java
│       │   │                   │   │   │       ├── OllamaMessage.java
│       │   │                   │   │   │       └── OllamaOptions.java
│       │   │                   │   │   ├── embedding/
│       │   │                   │   │   │   ├── OllamaEmbeddingService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── OllamaEmbedding.java
│       │   │                   │   │   │       └── OllamaEmbeddingResponse.java
│       │   │                   │   │   └── rerank/
│       │   │                   │   │       └── OllamaRerankService.java
│       │   │                   │   ├── openai/
│       │   │                   │   │   ├── audio/
│       │   │                   │   │   │   ├── OpenAiAudioService.java
│       │   │                   │   │   │   ├── entity/
│       │   │                   │   │   │   │   ├── Segment.java
│       │   │                   │   │   │   │   ├── TextToSpeech.java
│       │   │                   │   │   │   │   ├── Transcription.java
│       │   │                   │   │   │   │   ├── TranscriptionResponse.java
│       │   │                   │   │   │   │   ├── Translation.java
│       │   │                   │   │   │   │   ├── TranslationResponse.java
│       │   │                   │   │   │   │   └── Word.java
│       │   │                   │   │   │   └── enums/
│       │   │                   │   │   │       ├── AudioEnum.java
│       │   │                   │   │   │       └── WhisperEnum.java
│       │   │                   │   │   ├── chat/
│       │   │                   │   │   │   ├── OpenAiChatService.java
│       │   │                   │   │   │   ├── entity/
│       │   │                   │   │   │   │   ├── ChatCompletion.java
│       │   │                   │   │   │   │   ├── ChatCompletionResponse.java
│       │   │                   │   │   │   │   ├── ChatMessage.java
│       │   │                   │   │   │   │   ├── Choice.java
│       │   │                   │   │   │   │   ├── Content.java
│       │   │                   │   │   │   │   └── StreamOptions.java
│       │   │                   │   │   │   ├── enums/
│       │   │                   │   │   │   │   └── ChatMessageType.java
│       │   │                   │   │   │   └── serializer/
│       │   │                   │   │   │       └── ContentDeserializer.java
│       │   │                   │   │   ├── embedding/
│       │   │                   │   │   │   ├── OpenAiEmbeddingService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── Embedding.java
│       │   │                   │   │   │       ├── EmbeddingObject.java
│       │   │                   │   │   │       └── EmbeddingResponse.java
│       │   │                   │   │   ├── image/
│       │   │                   │   │   │   ├── OpenAiImageService.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── ImageData.java
│       │   │                   │   │   │       ├── ImageGeneration.java
│       │   │                   │   │   │       ├── ImageGenerationResponse.java
│       │   │                   │   │   │       ├── ImageStreamError.java
│       │   │                   │   │   │       ├── ImageStreamEvent.java
│       │   │                   │   │   │       ├── ImageUsage.java
│       │   │                   │   │   │       └── ImageUsageDetails.java
│       │   │                   │   │   ├── realtime/
│       │   │                   │   │   │   ├── OpenAiRealtimeService.java
│       │   │                   │   │   │   ├── RealtimeConstant.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── ConversationCreated.java
│       │   │                   │   │   │       ├── Session.java
│       │   │                   │   │   │       ├── SessionCreated.java
│       │   │                   │   │   │       └── SessionUpdated.java
│       │   │                   │   │   ├── response/
│       │   │                   │   │   │   ├── OpenAiResponsesService.java
│       │   │                   │   │   │   ├── ResponseEventParser.java
│       │   │                   │   │   │   └── entity/
│       │   │                   │   │   │       ├── ImagePixelLimit.java
│       │   │                   │   │   │       ├── Response.java
│       │   │                   │   │   │       ├── ResponseContentPart.java
│       │   │                   │   │   │       ├── ResponseContextEdit.java
│       │   │                   │   │   │       ├── ResponseContextManagement.java
│       │   │                   │   │   │       ├── ResponseDeleteResponse.java
│       │   │                   │   │   │       ├── ResponseError.java
│       │   │                   │   │   │       ├── ResponseIncompleteDetails.java
│       │   │                   │   │   │       ├── ResponseItem.java
│       │   │                   │   │   │       ├── ResponseRequest.java
│       │   │                   │   │   │       ├── ResponseStreamEvent.java
│       │   │                   │   │   │       ├── ResponseSummary.java
│       │   │                   │   │   │       ├── ResponseToolUsage.java
│       │   │                   │   │   │       ├── ResponseToolUsageDetails.java
│       │   │                   │   │   │       ├── ResponseUsage.java
│       │   │                   │   │   │       ├── ResponseUsageDetails.java
│       │   │                   │   │   │       └── TranslationOptions.java
│       │   │                   │   │   ├── tool/
│       │   │                   │   │   │   ├── Tool.java
│       │   │                   │   │   │   └── ToolCall.java
│       │   │                   │   │   └── usage/
│       │   │                   │   │       └── Usage.java
│       │   │                   │   ├── standard/
│       │   │                   │   │   └── rerank/
│       │   │                   │   │       └── StandardRerankService.java
│       │   │                   │   └── zhipu/
│       │   │                   │       └── chat/
│       │   │                   │           ├── ZhipuChatService.java
│       │   │                   │           └── entity/
│       │   │                   │               ├── ZhipuChatCompletion.java
│       │   │                   │               └── ZhipuChatCompletionResponse.java
│       │   │                   ├── rag/
│       │   │                   │   ├── AbstractScoreFusionStrategy.java
│       │   │                   │   ├── Bm25Retriever.java
│       │   │                   │   ├── DbsfFusionStrategy.java
│       │   │                   │   ├── DefaultRagContextAssembler.java
│       │   │                   │   ├── DefaultRagService.java
│       │   │                   │   ├── DefaultTextTokenizer.java
│       │   │                   │   ├── DenseRetriever.java
│       │   │                   │   ├── FusionStrategy.java
│       │   │                   │   ├── HybridRetriever.java
│       │   │                   │   ├── ModelReranker.java
│       │   │                   │   ├── NoopReranker.java
│       │   │                   │   ├── RagChunk.java
│       │   │                   │   ├── RagCitation.java
│       │   │                   │   ├── RagContext.java
│       │   │                   │   ├── RagContextAssembler.java
│       │   │                   │   ├── RagDocument.java
│       │   │                   │   ├── RagEvaluation.java
│       │   │                   │   ├── RagEvaluator.java
│       │   │                   │   ├── RagHit.java
│       │   │                   │   ├── RagHitSupport.java
│       │   │                   │   ├── RagMetadataKeys.java
│       │   │                   │   ├── RagQuery.java
│       │   │                   │   ├── RagResult.java
│       │   │                   │   ├── RagScoreDetail.java
│       │   │                   │   ├── RagService.java
│       │   │                   │   ├── RagTrace.java
│       │   │                   │   ├── Reranker.java
│       │   │                   │   ├── Retriever.java
│       │   │                   │   ├── RrfFusionStrategy.java
│       │   │                   │   ├── RsfFusionStrategy.java
│       │   │                   │   ├── TextTokenizer.java
│       │   │                   │   └── ingestion/
│       │   │                   │       ├── Chunker.java
│       │   │                   │       ├── DefaultMetadataEnricher.java
│       │   │                   │       ├── DocumentLoader.java
│       │   │                   │       ├── IngestionPipeline.java
│       │   │                   │       ├── IngestionRequest.java
│       │   │                   │       ├── IngestionResult.java
│       │   │                   │       ├── IngestionSource.java
│       │   │                   │       ├── LoadedDocument.java
│       │   │                   │       ├── LoadedDocumentProcessor.java
│       │   │                   │       ├── MetadataEnricher.java
│       │   │                   │       ├── OcrNoiseCleaningDocumentProcessor.java
│       │   │                   │       ├── OcrTextExtractingDocumentProcessor.java
│       │   │                   │       ├── OcrTextExtractor.java
│       │   │                   │       ├── RecursiveTextChunker.java
│       │   │                   │       ├── TextDocumentLoader.java
│       │   │                   │       ├── TikaDocumentLoader.java
│       │   │                   │       └── WhitespaceNormalizingDocumentProcessor.java
│       │   │                   ├── rerank/
│       │   │                   │   └── entity/
│       │   │                   │       ├── RerankDocument.java
│       │   │                   │       ├── RerankRequest.java
│       │   │                   │       ├── RerankResponse.java
│       │   │                   │       ├── RerankResult.java
│       │   │                   │       └── RerankUsage.java
│       │   │                   ├── service/
│       │   │                   │   ├── AiConfig.java
│       │   │                   │   ├── Configuration.java
│       │   │                   │   ├── IAudioService.java
│       │   │                   │   ├── IChatService.java
│       │   │                   │   ├── IEmbeddingService.java
│       │   │                   │   ├── IImageService.java
│       │   │                   │   ├── IRealtimeService.java
│       │   │                   │   ├── IRerankService.java
│       │   │                   │   ├── IResponsesService.java
│       │   │                   │   ├── ModelType.java
│       │   │                   │   ├── PlatformType.java
│       │   │                   │   ├── factory/
│       │   │                   │   │   ├── AiService.java
│       │   │                   │   │   ├── AiServiceFactory.java
│       │   │                   │   │   ├── AiServiceRegistration.java
│       │   │                   │   │   ├── AiServiceRegistry.java
│       │   │                   │   │   ├── DefaultAiServiceFactory.java
│       │   │                   │   │   ├── DefaultAiServiceRegistry.java
│       │   │                   │   │   └── FreeAiService.java
│       │   │                   │   └── spi/
│       │   │                   │       └── ServiceLoaderUtil.java
│       │   │                   ├── skill/
│       │   │                   │   ├── SkillDescriptor.java
│       │   │                   │   └── Skills.java
│       │   │                   ├── token/
│       │   │                   │   └── TikTokensUtil.java
│       │   │                   ├── tool/
│       │   │                   │   ├── BuiltInProcessRegistry.java
│       │   │                   │   ├── BuiltInToolContext.java
│       │   │                   │   ├── BuiltInToolExecutor.java
│       │   │                   │   ├── BuiltInTools.java
│       │   │                   │   ├── ResponseRequestToolResolver.java
│       │   │                   │   └── ToolUtil.java
│       │   │                   ├── tools/
│       │   │                   │   ├── ApplyPatchFunction.java
│       │   │                   │   ├── BashFunction.java
│       │   │                   │   ├── QueryTrainInfoFunction.java
│       │   │                   │   ├── QueryWeatherFunction.java
│       │   │                   │   ├── ReadFileFunction.java
│       │   │                   │   └── WriteFileFunction.java
│       │   │                   ├── vector/
│       │   │                   │   ├── VectorDataEntity.java
│       │   │                   │   ├── pinecone/
│       │   │                   │   │   ├── PineconeDelete.java
│       │   │                   │   │   ├── PineconeInsert.java
│       │   │                   │   │   ├── PineconeInsertResponse.java
│       │   │                   │   │   ├── PineconeQuery.java
│       │   │                   │   │   ├── PineconeQueryResponse.java
│       │   │                   │   │   └── PineconeVectors.java
│       │   │                   │   ├── service/
│       │   │                   │   │   └── PineconeService.java
│       │   │                   │   └── store/
│       │   │                   │       ├── VectorDeleteRequest.java
│       │   │                   │       ├── VectorRecord.java
│       │   │                   │       ├── VectorSearchRequest.java
│       │   │                   │       ├── VectorSearchResult.java
│       │   │                   │       ├── VectorStore.java
│       │   │                   │       ├── VectorStoreCapabilities.java
│       │   │                   │       ├── VectorUpsertRequest.java
│       │   │                   │       ├── milvus/
│       │   │                   │       │   └── MilvusVectorStore.java
│       │   │                   │       ├── pgvector/
│       │   │                   │       │   └── PgVectorStore.java
│       │   │                   │       ├── pinecone/
│       │   │                   │       │   └── PineconeVectorStore.java
│       │   │                   │       └── qdrant/
│       │   │                   │           └── QdrantVectorStore.java
│       │   │                   └── websearch/
│       │   │                       ├── ChatWithWebSearchEnhance.java
│       │   │                       └── searxng/
│       │   │                           ├── SearXNGConfig.java
│       │   │                           ├── SearXNGRequest.java
│       │   │                           └── SearXNGResponse.java
│       │   └── resources/
│       │       ├── META-INF/
│       │       │   └── services/
│       │       │       ├── io.github.lnyocly.ai4j.network.ConnectionPoolProvider
│       │       │       └── io.github.lnyocly.ai4j.network.DispatcherProvider
│       │       └── mcp-servers-config.json
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           ├── BaichuanTest.java
│                           ├── DashScopeTest.java
│                           ├── DeepSeekTest.java
│                           ├── DoubaoImageTest.java
│                           ├── DoubaoResponsesTest.java
│                           ├── DoubaoTest.java
│                           ├── HunyuanTest.java
│                           ├── LingyiTest.java
│                           ├── MinimaxTest.java
│                           ├── MoonshotTest.java
│                           ├── OllamaTest.java
│                           ├── OpenAiTest.java
│                           ├── OtherTest.java
│                           ├── ZhipuTest.java
│                           ├── ai4j/
│                           │   ├── agentflow/
│                           │   │   ├── AgentFlowTraceSupportTest.java
│                           │   │   ├── CozeAgentFlowServiceTest.java
│                           │   │   ├── DifyAgentFlowServiceTest.java
│                           │   │   └── N8nAgentFlowWorkflowServiceTest.java
│                           │   ├── function/
│                           │   │   └── TestFunction.java
│                           │   ├── mcp/
│                           │   │   ├── McpClientResponseSupportTest.java
│                           │   │   ├── McpGatewaySupportTest.java
│                           │   │   ├── McpServerTest.java
│                           │   │   ├── McpTypeSupportTest.java
│                           │   │   ├── TestMcpService.java
│                           │   │   ├── config/
│                           │   │   │   └── McpConfigManagerTest.java
│                           │   │   ├── gateway/
│                           │   │   │   └── McpGatewayConfigSourceTest.java
│                           │   │   ├── transport/
│                           │   │   │   └── SseTransportTest.java
│                           │   │   └── util/
│                           │   │       └── TestMcpService.java
│                           │   ├── memory/
│                           │   │   ├── InMemoryChatMemoryTest.java
│                           │   │   ├── JdbcChatMemoryTest.java
│                           │   │   └── SummaryChatMemoryPolicyTest.java
│                           │   ├── platform/
│                           │   │   ├── doubao/
│                           │   │   │   └── rerank/
│                           │   │   │       └── DoubaoRerankServiceTest.java
│                           │   │   ├── jina/
│                           │   │   │   └── rerank/
│                           │   │   │       └── JinaRerankServiceTest.java
│                           │   │   ├── minimax/
│                           │   │   │   └── chat/
│                           │   │   │       └── MinimaxChatServiceTest.java
│                           │   │   ├── ollama/
│                           │   │   │   └── rerank/
│                           │   │   │       └── OllamaRerankServiceTest.java
│                           │   │   └── openai/
│                           │   │       ├── audio/
│                           │   │       │   └── OpenAiAudioServiceTest.java
│                           │   │       ├── chat/
│                           │   │       │   └── OpenAiChatServicePassThroughTest.java
│                           │   │       └── response/
│                           │   │           └── ResponseRequestToolResolverTest.java
│                           │   ├── rag/
│                           │   │   ├── Bm25RetrieverTest.java
│                           │   │   ├── DefaultRagServiceTest.java
│                           │   │   ├── DenseRetrieverTest.java
│                           │   │   ├── HybridRetrieverTest.java
│                           │   │   ├── IngestionPipelineTest.java
│                           │   │   ├── ModelRerankerTest.java
│                           │   │   └── RagEvaluatorTest.java
│                           │   ├── skill/
│                           │   │   └── SkillsIChatServiceTest.java
│                           │   ├── tool/
│                           │   │   └── BuiltInToolExecutorTest.java
│                           │   └── vector/
│                           │       └── store/
│                           │           ├── milvus/
│                           │           │   └── MilvusVectorStoreTest.java
│                           │           ├── pinecone/
│                           │           │   └── PineconeVectorStoreTest.java
│                           │           └── qdrant/
│                           │               └── QdrantVectorStoreTest.java
│                           ├── interceptor/
│                           │   └── ErrorInterceptorTest.java
│                           ├── listener/
│                           │   ├── SseListenerTest.java
│                           │   └── StreamExecutionSupportTest.java
│                           └── service/
│                               └── AiServiceRegistryTest.java
├── ai4j-agent/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── io/
│       │           └── github/
│       │               └── lnyocly/
│       │                   └── ai4j/
│       │                       └── agent/
│       │                           ├── Agent.java
│       │                           ├── AgentBuilder.java
│       │                           ├── AgentContext.java
│       │                           ├── AgentOptions.java
│       │                           ├── AgentRequest.java
│       │                           ├── AgentResult.java
│       │                           ├── AgentRuntime.java
│       │                           ├── AgentSession.java
│       │                           ├── Agents.java
│       │                           ├── codeact/
│       │                           │   ├── CodeActOptions.java
│       │                           │   ├── CodeExecutionRequest.java
│       │                           │   ├── CodeExecutionResult.java
│       │                           │   ├── CodeExecutor.java
│       │                           │   ├── GraalVmCodeExecutor.java
│       │                           │   └── NashornCodeExecutor.java
│       │                           ├── event/
│       │                           │   ├── AgentEvent.java
│       │                           │   ├── AgentEventPublisher.java
│       │                           │   ├── AgentEventType.java
│       │                           │   └── AgentListener.java
│       │                           ├── flowgram/
│       │                           │   ├── Ai4jFlowGramLlmNodeRunner.java
│       │                           │   ├── FlowGramLlmNodeRunner.java
│       │                           │   ├── FlowGramNodeExecutionContext.java
│       │                           │   ├── FlowGramNodeExecutionResult.java
│       │                           │   ├── FlowGramNodeExecutor.java
│       │                           │   ├── FlowGramRuntimeEvent.java
│       │                           │   ├── FlowGramRuntimeListener.java
│       │                           │   ├── FlowGramRuntimeService.java
│       │                           │   └── model/
│       │                           │       ├── FlowGramEdgeSchema.java
│       │                           │       ├── FlowGramNodeSchema.java
│       │                           │       ├── FlowGramTaskCancelOutput.java
│       │                           │       ├── FlowGramTaskReportOutput.java
│       │                           │       ├── FlowGramTaskResultOutput.java
│       │                           │       ├── FlowGramTaskRunInput.java
│       │                           │       ├── FlowGramTaskRunOutput.java
│       │                           │       ├── FlowGramTaskValidateOutput.java
│       │                           │       └── FlowGramWorkflowSchema.java
│       │                           ├── memory/
│       │                           │   ├── AgentMemory.java
│       │                           │   ├── InMemoryAgentMemory.java
│       │                           │   ├── JdbcAgentMemory.java
│       │                           │   ├── JdbcAgentMemoryConfig.java
│       │                           │   ├── MemoryCompressor.java
│       │                           │   ├── MemorySnapshot.java
│       │                           │   └── WindowedMemoryCompressor.java
│       │                           ├── model/
│       │                           │   ├── AgentModelClient.java
│       │                           │   ├── AgentModelResult.java
│       │                           │   ├── AgentModelStreamListener.java
│       │                           │   ├── AgentPrompt.java
│       │                           │   ├── ChatModelClient.java
│       │                           │   └── ResponsesModelClient.java
│       │                           ├── runtime/
│       │                           │   ├── AgentToolExecutionScope.java
│       │                           │   ├── BaseAgentRuntime.java
│       │                           │   ├── CodeActRuntime.java
│       │                           │   ├── DeepResearchRuntime.java
│       │                           │   ├── Planner.java
│       │                           │   └── ReActRuntime.java
│       │                           ├── subagent/
│       │                           │   ├── HandoffContext.java
│       │                           │   ├── HandoffFailureAction.java
│       │                           │   ├── HandoffInputFilter.java
│       │                           │   ├── HandoffPolicy.java
│       │                           │   ├── StaticSubAgentRegistry.java
│       │                           │   ├── SubAgentDefinition.java
│       │                           │   ├── SubAgentRegistry.java
│       │                           │   ├── SubAgentSessionMode.java
│       │                           │   └── SubAgentToolExecutor.java
│       │                           ├── team/
│       │                           │   ├── AgentTeam.java
│       │                           │   ├── AgentTeamAgentRuntime.java
│       │                           │   ├── AgentTeamBuilder.java
│       │                           │   ├── AgentTeamControl.java
│       │                           │   ├── AgentTeamEventHook.java
│       │                           │   ├── AgentTeamHook.java
│       │                           │   ├── AgentTeamMember.java
│       │                           │   ├── AgentTeamMemberResult.java
│       │                           │   ├── AgentTeamMemberSnapshot.java
│       │                           │   ├── AgentTeamMessage.java
│       │                           │   ├── AgentTeamMessageBus.java
│       │                           │   ├── AgentTeamOptions.java
│       │                           │   ├── AgentTeamPlan.java
│       │                           │   ├── AgentTeamPlanApproval.java
│       │                           │   ├── AgentTeamPlanParser.java
│       │                           │   ├── AgentTeamPlanner.java
│       │                           │   ├── AgentTeamResult.java
│       │                           │   ├── AgentTeamState.java
│       │                           │   ├── AgentTeamStateStore.java
│       │                           │   ├── AgentTeamSynthesizer.java
│       │                           │   ├── AgentTeamTask.java
│       │                           │   ├── AgentTeamTaskBoard.java
│       │                           │   ├── AgentTeamTaskState.java
│       │                           │   ├── AgentTeamTaskStatus.java
│       │                           │   ├── FileAgentTeamMessageBus.java
│       │                           │   ├── FileAgentTeamStateStore.java
│       │                           │   ├── InMemoryAgentTeamMessageBus.java
│       │                           │   ├── InMemoryAgentTeamStateStore.java
│       │                           │   ├── LlmAgentTeamPlanner.java
│       │                           │   ├── LlmAgentTeamSynthesizer.java
│       │                           │   └── tool/
│       │                           │       ├── AgentTeamToolExecutor.java
│       │                           │       └── AgentTeamToolRegistry.java
│       │                           ├── tool/
│       │                           │   ├── AgentToolCall.java
│       │                           │   ├── AgentToolCallSanitizer.java
│       │                           │   ├── AgentToolRegistry.java
│       │                           │   ├── AgentToolResult.java
│       │                           │   ├── CompositeToolRegistry.java
│       │                           │   ├── StaticToolRegistry.java
│       │                           │   ├── ToolExecutor.java
│       │                           │   ├── ToolUtilExecutor.java
│       │                           │   └── ToolUtilRegistry.java
│       │                           ├── trace/
│       │                           │   ├── AbstractOpenTelemetryTraceExporter.java
│       │                           │   ├── AgentFlowTraceBridge.java
│       │                           │   ├── AgentTraceListener.java
│       │                           │   ├── CompositeTraceExporter.java
│       │                           │   ├── ConsoleTraceExporter.java
│       │                           │   ├── InMemoryTraceExporter.java
│       │                           │   ├── JsonlTraceExporter.java
│       │                           │   ├── LangfuseTraceExporter.java
│       │                           │   ├── OpenTelemetryTraceExporter.java
│       │                           │   ├── OpenTelemetryTraceSupport.java
│       │                           │   ├── TraceConfig.java
│       │                           │   ├── TraceExporter.java
│       │                           │   ├── TraceMasker.java
│       │                           │   ├── TraceMetrics.java
│       │                           │   ├── TracePricing.java
│       │                           │   ├── TracePricingResolver.java
│       │                           │   ├── TraceSpan.java
│       │                           │   ├── TraceSpanEvent.java
│       │                           │   ├── TraceSpanStatus.java
│       │                           │   └── TraceSpanType.java
│       │                           ├── util/
│       │                           │   ├── AgentInputItem.java
│       │                           │   └── ResponseUtil.java
│       │                           └── workflow/
│       │                               ├── AgentNode.java
│       │                               ├── AgentWorkflow.java
│       │                               ├── RuntimeAgentNode.java
│       │                               ├── SequentialWorkflow.java
│       │                               ├── StateCondition.java
│       │                               ├── StateGraphWorkflow.java
│       │                               ├── StateRouter.java
│       │                               ├── StateTransition.java
│       │                               ├── WorkflowAgent.java
│       │                               ├── WorkflowContext.java
│       │                               └── WorkflowResultAware.java
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           ├── agent/
│                           │   ├── AgentFlowTraceBridgeTest.java
│                           │   ├── AgentMemoryTest.java
│                           │   ├── AgentRuntimeTest.java
│                           │   ├── AgentTeamAgentAdapterTest.java
│                           │   ├── AgentTeamPersistenceTest.java
│                           │   ├── AgentTeamProjectDeliveryExampleTest.java
│                           │   ├── AgentTeamTaskBoardTest.java
│                           │   ├── AgentTeamTest.java
│                           │   ├── AgentTeamUsageTest.java
│                           │   ├── AgentTraceListenerTest.java
│                           │   ├── AgentTraceUsageTest.java
│                           │   ├── AgentWorkflowTest.java
│                           │   ├── AgentWorkflowUsageTest.java
│                           │   ├── ChatModelClientTest.java
│                           │   ├── CodeActAgentUsageTest.java
│                           │   ├── CodeActPythonExecutorTest.java
│                           │   ├── CodeActRuntimeTest.java
│                           │   ├── CodeActRuntimeWithTraceTest.java
│                           │   ├── DoubaoAgentTeamBestPracticeTest.java
│                           │   ├── DoubaoAgentWorkflowTest.java
│                           │   ├── DoubaoProjectTeamAgentTeamsTest.java
│                           │   ├── FileAgentTeamStateStoreTest.java
│                           │   ├── HandoffPolicyTest.java
│                           │   ├── MinimaxAgentTeamTravelUsageTest.java
│                           │   ├── NashornCodeExecutorTest.java
│                           │   ├── ReActAgentUsageTest.java
│                           │   ├── ResponsesModelClientTest.java
│                           │   ├── StateGraphWorkflowTest.java
│                           │   ├── SubAgentParallelFallbackTest.java
│                           │   ├── SubAgentRuntimeTest.java
│                           │   ├── SubAgentUsageTest.java
│                           │   ├── ToolUtilExecutorRestrictionTest.java
│                           │   ├── UniversalAgentUsageTest.java
│                           │   ├── WeatherAgentWorkflowTest.java
│                           │   └── support/
│                           │       └── ZhipuAgentTestSupport.java
│                           └── ai4j/
│                               └── agent/
│                                   ├── flowgram/
│                                   │   └── FlowGramRuntimeServiceTest.java
│                                   ├── memory/
│                                   │   └── JdbcAgentMemoryTest.java
│                                   ├── model/
│                                   │   └── ChatModelClientTest.java
│                                   └── trace/
│                                       └── LangfuseTraceExporterTest.java
├── ai4j-bom/
│   └── pom.xml
├── ai4j-cli/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── github/
│       │   │           └── lnyocly/
│       │   │               └── ai4j/
│       │   │                   ├── cli/
│       │   │                   │   ├── Ai4jCli.java
│       │   │                   │   ├── Ai4jCliMain.java
│       │   │                   │   ├── ApprovalMode.java
│       │   │                   │   ├── CliProtocol.java
│       │   │                   │   ├── CliUiMode.java
│       │   │                   │   ├── SlashCommandController.java
│       │   │                   │   ├── acp/
│       │   │                   │   │   ├── AcpCodingCliAgentFactory.java
│       │   │                   │   │   ├── AcpCommand.java
│       │   │                   │   │   ├── AcpJsonRpcServer.java
│       │   │                   │   │   ├── AcpSlashCommandSupport.java
│       │   │                   │   │   └── AcpToolApprovalDecorator.java
│       │   │                   │   ├── agent/
│       │   │                   │   │   └── CliCodingAgentRegistry.java
│       │   │                   │   ├── command/
│       │   │                   │   │   ├── CodeCommand.java
│       │   │                   │   │   ├── CodeCommandOptions.java
│       │   │                   │   │   ├── CodeCommandOptionsParser.java
│       │   │                   │   │   ├── CustomCommandRegistry.java
│       │   │                   │   │   └── CustomCommandTemplate.java
│       │   │                   │   ├── config/
│       │   │                   │   │   └── CliWorkspaceConfig.java
│       │   │                   │   ├── factory/
│       │   │                   │   │   ├── CodingCliAgentFactory.java
│       │   │                   │   │   ├── CodingCliTuiFactory.java
│       │   │                   │   │   ├── DefaultCodingCliAgentFactory.java
│       │   │                   │   │   └── DefaultCodingCliTuiFactory.java
│       │   │                   │   ├── mcp/
│       │   │                   │   │   ├── CliMcpConfig.java
│       │   │                   │   │   ├── CliMcpConfigManager.java
│       │   │                   │   │   ├── CliMcpConnectionHandle.java
│       │   │                   │   │   ├── CliMcpRuntimeManager.java
│       │   │                   │   │   ├── CliMcpServerDefinition.java
│       │   │                   │   │   ├── CliMcpStatusSnapshot.java
│       │   │                   │   │   ├── CliResolvedMcpConfig.java
│       │   │                   │   │   └── CliResolvedMcpServer.java
│       │   │                   │   ├── provider/
│       │   │                   │   │   ├── CliProviderConfigManager.java
│       │   │                   │   │   ├── CliProviderProfile.java
│       │   │                   │   │   ├── CliProvidersConfig.java
│       │   │                   │   │   └── CliResolvedProviderConfig.java
│       │   │                   │   ├── render/
│       │   │                   │   │   ├── AssistantTranscriptRenderer.java
│       │   │                   │   │   ├── CliAnsi.java
│       │   │                   │   │   ├── CliDisplayWidth.java
│       │   │                   │   │   ├── CliThemeStyler.java
│       │   │                   │   │   ├── CodexStyleBlockFormatter.java
│       │   │                   │   │   ├── PatchSummaryFormatter.java
│       │   │                   │   │   └── TranscriptPrinter.java
│       │   │                   │   ├── runtime/
│       │   │                   │   │   ├── AgentHandoffSessionEventSupport.java
│       │   │                   │   │   ├── AgentTeamMessageSessionEventSupport.java
│       │   │                   │   │   ├── AgentTeamSessionEventSupport.java
│       │   │                   │   │   ├── CliTeamStateManager.java
│       │   │                   │   │   ├── CliToolApprovalDecorator.java
│       │   │                   │   │   ├── CodingCliSessionRunner.java
│       │   │                   │   │   ├── CodingCliTuiSupport.java
│       │   │                   │   │   ├── CodingTaskSessionEventBridge.java
│       │   │                   │   │   ├── HeadlessCodingSessionRuntime.java
│       │   │                   │   │   ├── HeadlessTurnObserver.java
│       │   │                   │   │   └── TeamBoardRenderSupport.java
│       │   │                   │   ├── session/
│       │   │                   │   │   ├── CodingSessionManager.java
│       │   │                   │   │   ├── CodingSessionStore.java
│       │   │                   │   │   ├── DefaultCodingSessionManager.java
│       │   │                   │   │   ├── FileCodingSessionStore.java
│       │   │                   │   │   ├── FileSessionEventStore.java
│       │   │                   │   │   ├── InMemoryCodingSessionStore.java
│       │   │                   │   │   ├── InMemorySessionEventStore.java
│       │   │                   │   │   ├── SessionEventStore.java
│       │   │                   │   │   └── StoredCodingSession.java
│       │   │                   │   └── shell/
│       │   │                   │       ├── JlineCodeCommandRunner.java
│       │   │                   │       ├── JlineShellContext.java
│       │   │                   │       ├── JlineShellTerminalIO.java
│       │   │                   │       └── WindowsConsoleKeyPoller.java
│       │   │                   └── tui/
│       │   │                       ├── AnsiTuiRuntime.java
│       │   │                       ├── AppendOnlyTuiRuntime.java
│       │   │                       ├── JlineTerminalIO.java
│       │   │                       ├── StreamsTerminalIO.java
│       │   │                       ├── TerminalIO.java
│       │   │                       ├── TuiAnsi.java
│       │   │                       ├── TuiAssistantPhase.java
│       │   │                       ├── TuiAssistantToolView.java
│       │   │                       ├── TuiAssistantViewModel.java
│       │   │                       ├── TuiConfig.java
│       │   │                       ├── TuiConfigManager.java
│       │   │                       ├── TuiInteractionState.java
│       │   │                       ├── TuiKeyStroke.java
│       │   │                       ├── TuiKeyType.java
│       │   │                       ├── TuiPaletteItem.java
│       │   │                       ├── TuiPanelId.java
│       │   │                       ├── TuiRenderContext.java
│       │   │                       ├── TuiRenderer.java
│       │   │                       ├── TuiRuntime.java
│       │   │                       ├── TuiScreenModel.java
│       │   │                       ├── TuiSessionView.java
│       │   │                       ├── TuiTheme.java
│       │   │                       ├── io/
│       │   │                       │   ├── DefaultJlineTerminalIO.java
│       │   │                       │   └── DefaultStreamsTerminalIO.java
│       │   │                       └── runtime/
│       │   │                           ├── DefaultAnsiTuiRuntime.java
│       │   │                           └── DefaultAppendOnlyTuiRuntime.java
│       │   └── resources/
│       │       └── io/
│       │           └── github/
│       │               └── lnyocly/
│       │                   └── ai4j/
│       │                       └── tui/
│       │                           └── themes/
│       │                               ├── amber.json
│       │                               ├── default.json
│       │                               ├── github-dark.json
│       │                               ├── github-light.json
│       │                               ├── matrix.json
│       │                               └── ocean.json
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           └── ai4j/
│                               ├── cli/
│                               │   ├── Ai4jCliTest.java
│                               │   ├── AssistantTranscriptRendererTest.java
│                               │   ├── CliDisplayWidthTest.java
│                               │   ├── CliMcpConfigManagerTest.java
│                               │   ├── CliMcpRuntimeManagerTest.java
│                               │   ├── CliProviderConfigManagerTest.java
│                               │   ├── CliThemeStylerTest.java
│                               │   ├── CodeCommandOptionsParserTest.java
│                               │   ├── CodeCommandTest.java
│                               │   ├── CodexStyleBlockFormatterTest.java
│                               │   ├── DefaultCodingCliAgentFactoryTest.java
│                               │   ├── DefaultCodingSessionManagerTest.java
│                               │   ├── FileCodingSessionStoreTest.java
│                               │   ├── FileSessionEventStoreTest.java
│                               │   ├── JlineShellTerminalIOTest.java
│                               │   ├── PatchSummaryFormatterTest.java
│                               │   ├── SlashCommandControllerTest.java
│                               │   ├── TranscriptPrinterTest.java
│                               │   ├── acp/
│                               │   │   ├── AcpCommandTest.java
│                               │   │   └── AcpSlashCommandSupportTest.java
│                               │   ├── agent/
│                               │   │   └── CliCodingAgentRegistryTest.java
│                               │   └── runtime/
│                               │       ├── AgentHandoffSessionEventSupportTest.java
│                               │       ├── AgentTeamMessageSessionEventSupportTest.java
│                               │       ├── AgentTeamSessionEventSupportTest.java
│                               │       ├── CodingTaskSessionEventBridgeTest.java
│                               │       └── HeadlessCodingSessionRuntimeTest.java
│                               └── tui/
│                                   ├── AnsiTuiRuntimeTest.java
│                                   ├── AppendOnlyTuiRuntimeTest.java
│                                   ├── StreamsTerminalIOTest.java
│                                   ├── TuiConfigManagerTest.java
│                                   ├── TuiInteractionStateTest.java
│                                   └── TuiSessionViewTest.java
├── ai4j-coding/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── io/
│       │           └── github/
│       │               └── lnyocly/
│       │                   └── ai4j/
│       │                       └── coding/
│       │                           ├── CodingAgent.java
│       │                           ├── CodingAgentBuilder.java
│       │                           ├── CodingAgentOptions.java
│       │                           ├── CodingAgentRequest.java
│       │                           ├── CodingAgentResult.java
│       │                           ├── CodingAgents.java
│       │                           ├── CodingSession.java
│       │                           ├── CodingSessionCheckpoint.java
│       │                           ├── CodingSessionCheckpointFormatter.java
│       │                           ├── CodingSessionCompactResult.java
│       │                           ├── CodingSessionScope.java
│       │                           ├── CodingSessionSnapshot.java
│       │                           ├── CodingSessionState.java
│       │                           ├── compact/
│       │                           │   ├── CodingCompactionPreparation.java
│       │                           │   ├── CodingSessionCompactor.java
│       │                           │   ├── CodingToolResultMicroCompactResult.java
│       │                           │   └── CodingToolResultMicroCompactor.java
│       │                           ├── definition/
│       │                           │   ├── BuiltInCodingAgentDefinitions.java
│       │                           │   ├── CodingAgentDefinition.java
│       │                           │   ├── CodingAgentDefinitionRegistry.java
│       │                           │   ├── CodingApprovalMode.java
│       │                           │   ├── CodingIsolationMode.java
│       │                           │   ├── CodingMemoryScope.java
│       │                           │   ├── CodingSessionMode.java
│       │                           │   ├── CompositeCodingAgentDefinitionRegistry.java
│       │                           │   └── StaticCodingAgentDefinitionRegistry.java
│       │                           ├── delegate/
│       │                           │   ├── CodingDelegateRequest.java
│       │                           │   ├── CodingDelegateResult.java
│       │                           │   ├── CodingDelegateToolExecutor.java
│       │                           │   └── CodingDelegateToolRegistry.java
│       │                           ├── loop/
│       │                           │   ├── CodingAgentLoopController.java
│       │                           │   ├── CodingContinuationPrompt.java
│       │                           │   ├── CodingLoopDecision.java
│       │                           │   ├── CodingLoopPolicy.java
│       │                           │   └── CodingStopReason.java
│       │                           ├── patch/
│       │                           │   ├── ApplyPatchFileChange.java
│       │                           │   └── ApplyPatchResult.java
│       │                           ├── policy/
│       │                           │   ├── CodingToolContextPolicy.java
│       │                           │   └── CodingToolPolicyResolver.java
│       │                           ├── process/
│       │                           │   ├── BashProcessInfo.java
│       │                           │   ├── BashProcessLogChunk.java
│       │                           │   ├── BashProcessStatus.java
│       │                           │   ├── SessionProcessRegistry.java
│       │                           │   └── StoredProcessSnapshot.java
│       │                           ├── prompt/
│       │                           │   └── CodingContextPromptAssembler.java
│       │                           ├── runtime/
│       │                           │   ├── CodingRuntime.java
│       │                           │   ├── CodingRuntimeListener.java
│       │                           │   └── DefaultCodingRuntime.java
│       │                           ├── session/
│       │                           │   ├── CodingSessionDescriptor.java
│       │                           │   ├── CodingSessionLink.java
│       │                           │   ├── CodingSessionLinkStore.java
│       │                           │   ├── InMemoryCodingSessionLinkStore.java
│       │                           │   ├── ManagedCodingSession.java
│       │                           │   ├── SessionEvent.java
│       │                           │   └── SessionEventType.java
│       │                           ├── shell/
│       │                           │   ├── LocalShellCommandExecutor.java
│       │                           │   ├── ShellCommandExecutor.java
│       │                           │   ├── ShellCommandRequest.java
│       │                           │   ├── ShellCommandResult.java
│       │                           │   └── ShellCommandSupport.java
│       │                           ├── skill/
│       │                           │   ├── CodingSkillDescriptor.java
│       │                           │   └── CodingSkillDiscovery.java
│       │                           ├── task/
│       │                           │   ├── CodingTask.java
│       │                           │   ├── CodingTaskManager.java
│       │                           │   ├── CodingTaskProgress.java
│       │                           │   ├── CodingTaskStatus.java
│       │                           │   └── InMemoryCodingTaskManager.java
│       │                           ├── tool/
│       │                           │   ├── ApplyPatchToolExecutor.java
│       │                           │   ├── BashToolExecutor.java
│       │                           │   ├── CodingToolNames.java
│       │                           │   ├── CodingToolRegistryFactory.java
│       │                           │   ├── ReadFileToolExecutor.java
│       │                           │   ├── RoutingToolExecutor.java
│       │                           │   ├── ToolExecutorDecorator.java
│       │                           │   └── WriteFileToolExecutor.java
│       │                           └── workspace/
│       │                               ├── LocalWorkspaceFileService.java
│       │                               ├── WorkspaceContext.java
│       │                               ├── WorkspaceEntry.java
│       │                               ├── WorkspaceFileReadResult.java
│       │                               ├── WorkspaceFileService.java
│       │                               └── WorkspaceWriteResult.java
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           └── ai4j/
│                               └── coding/
│                                   ├── ApplyPatchToolExecutorTest.java
│                                   ├── BashToolExecutorTest.java
│                                   ├── CodingAgentBuilderTest.java
│                                   ├── CodingRuntimeTest.java
│                                   ├── CodingSessionCheckpointFormatterTest.java
│                                   ├── CodingSessionTest.java
│                                   ├── CodingSkillSupportTest.java
│                                   ├── LocalShellCommandExecutorTest.java
│                                   ├── MinimaxCodingAgentTeamWorkspaceUsageTest.java
│                                   ├── ReadFileToolExecutorTest.java
│                                   ├── WriteFileToolExecutorTest.java
│                                   ├── loop/
│                                   │   └── CodingAgentLoopControllerTest.java
│                                   └── shell/
│                                       └── ShellCommandSupportTest.java
├── ai4j-flowgram-demo/
│   ├── README.md
│   ├── backend-18080-run.log
│   ├── backend-18080.log
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── io/
│           │       └── github/
│           │           └── lnyocly/
│           │               └── ai4j/
│           │                   └── flowgram/
│           │                       └── demo/
│           │                           ├── FlowGramDemoApplication.java
│           │                           └── FlowGramDemoMockController.java
│           └── resources/
│               └── application.yml
├── ai4j-flowgram-spring-boot-starter/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── github/
│       │   │           └── lnyocly/
│       │   │               └── ai4j/
│       │   │                   └── flowgram/
│       │   │                       └── springboot/
│       │   │                           ├── adapter/
│       │   │                           │   └── FlowGramProtocolAdapter.java
│       │   │                           ├── autoconfigure/
│       │   │                           │   └── FlowGramAutoConfiguration.java
│       │   │                           ├── config/
│       │   │                           │   └── FlowGramProperties.java
│       │   │                           ├── controller/
│       │   │                           │   └── FlowGramTaskController.java
│       │   │                           ├── dto/
│       │   │                           │   ├── FlowGramErrorResponse.java
│       │   │                           │   ├── FlowGramTaskCancelResponse.java
│       │   │                           │   ├── FlowGramTaskReportResponse.java
│       │   │                           │   ├── FlowGramTaskResultResponse.java
│       │   │                           │   ├── FlowGramTaskRunRequest.java
│       │   │                           │   ├── FlowGramTaskRunResponse.java
│       │   │                           │   ├── FlowGramTaskValidateRequest.java
│       │   │                           │   ├── FlowGramTaskValidateResponse.java
│       │   │                           │   └── FlowGramTraceView.java
│       │   │                           ├── exception/
│       │   │                           │   ├── FlowGramAccessDeniedException.java
│       │   │                           │   ├── FlowGramApiException.java
│       │   │                           │   ├── FlowGramExceptionHandler.java
│       │   │                           │   └── FlowGramTaskNotFoundException.java
│       │   │                           ├── node/
│       │   │                           │   ├── FlowGramCodeNodeExecutor.java
│       │   │                           │   ├── FlowGramHttpNodeExecutor.java
│       │   │                           │   ├── FlowGramKnowledgeRetrieveNodeExecutor.java
│       │   │                           │   ├── FlowGramNodeValueResolver.java
│       │   │                           │   ├── FlowGramToolNodeExecutor.java
│       │   │                           │   └── FlowGramVariableNodeExecutor.java
│       │   │                           ├── security/
│       │   │                           │   ├── DefaultFlowGramAccessChecker.java
│       │   │                           │   ├── DefaultFlowGramCallerResolver.java
│       │   │                           │   ├── DefaultFlowGramTaskOwnershipStrategy.java
│       │   │                           │   ├── FlowGramAccessChecker.java
│       │   │                           │   ├── FlowGramAction.java
│       │   │                           │   ├── FlowGramCaller.java
│       │   │                           │   ├── FlowGramCallerResolver.java
│       │   │                           │   ├── FlowGramTaskOwnership.java
│       │   │                           │   └── FlowGramTaskOwnershipStrategy.java
│       │   │                           └── support/
│       │   │                               ├── FlowGramRuntimeFacade.java
│       │   │                               ├── FlowGramRuntimeTraceCollector.java
│       │   │                               ├── FlowGramStoredTask.java
│       │   │                               ├── FlowGramTaskStore.java
│       │   │                               ├── FlowGramTraceResponseEnricher.java
│       │   │                               ├── InMemoryFlowGramTaskStore.java
│       │   │                               ├── JdbcFlowGramTaskStore.java
│       │   │                               └── RegistryBackedFlowGramModelClientResolver.java
│       │   └── resources/
│       │       └── META-INF/
│       │           ├── spring/
│       │           │   └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│       │           └── spring.factories
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           └── ai4j/
│                               └── flowgram/
│                                   └── springboot/
│                                       ├── FlowGramJdbcTaskStoreAutoConfigurationTest.java
│                                       ├── FlowGramRuntimeTraceCollectorTest.java
│                                       ├── FlowGramTaskControllerIntegrationTest.java
│                                       ├── node/
│                                       │   ├── FlowGramBuiltinNodeExecutorTest.java
│                                       │   └── FlowGramKnowledgeRetrieveNodeExecutorTest.java
│                                       └── support/
│                                           └── JdbcFlowGramTaskStoreTest.java
├── ai4j-flowgram-webapp-demo/
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── README.md
│   ├── README.zh_CN.md
│   ├── index.html
│   ├── package.json
│   ├── rsbuild.config.ts
│   ├── src/
│   │   ├── app.tsx
│   │   ├── assets/
│   │   │   ├── icon-auto-layout.tsx
│   │   │   ├── icon-cancel.tsx
│   │   │   ├── icon-comment.tsx
│   │   │   ├── icon-minimap.tsx
│   │   │   ├── icon-mouse.tsx
│   │   │   ├── icon-pad.tsx
│   │   │   ├── icon-success.tsx
│   │   │   ├── icon-switch-line.tsx
│   │   │   └── icon-warning.tsx
│   │   ├── components/
│   │   │   ├── add-node/
│   │   │   │   ├── index.tsx
│   │   │   │   └── use-add-node.ts
│   │   │   ├── base-node/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── node-wrapper.tsx
│   │   │   │   ├── styles.tsx
│   │   │   │   └── utils.ts
│   │   │   ├── comment/
│   │   │   │   ├── components/
│   │   │   │   │   ├── blank-area.tsx
│   │   │   │   │   ├── border-area.tsx
│   │   │   │   │   ├── container.tsx
│   │   │   │   │   ├── content-drag-area.tsx
│   │   │   │   │   ├── drag-area.tsx
│   │   │   │   │   ├── editor.tsx
│   │   │   │   │   ├── index.css
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── more-button.tsx
│   │   │   │   │   ├── render.tsx
│   │   │   │   │   └── resize-area.tsx
│   │   │   │   ├── constant.ts
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── use-model.ts
│   │   │   │   │   ├── use-overflow.ts
│   │   │   │   │   ├── use-placeholder.ts
│   │   │   │   │   └── use-size.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── model.ts
│   │   │   │   └── type.ts
│   │   │   ├── group/
│   │   │   │   ├── color.ts
│   │   │   │   ├── components/
│   │   │   │   │   ├── background.tsx
│   │   │   │   │   ├── color.tsx
│   │   │   │   │   ├── header.tsx
│   │   │   │   │   ├── icon-group.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── node-render.tsx
│   │   │   │   │   ├── tips/
│   │   │   │   │   │   ├── global-store.ts
│   │   │   │   │   │   ├── icon-close.tsx
│   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   ├── is-mac-os.ts
│   │   │   │   │   │   ├── style.ts
│   │   │   │   │   │   └── use-control.ts
│   │   │   │   │   ├── title.tsx
│   │   │   │   │   ├── tools.tsx
│   │   │   │   │   └── ungroup.tsx
│   │   │   │   ├── constant.ts
│   │   │   │   ├── index.css
│   │   │   │   └── index.ts
│   │   │   ├── index.ts
│   │   │   ├── line-add-button/
│   │   │   │   ├── button.tsx
│   │   │   │   ├── index.less
│   │   │   │   ├── index.tsx
│   │   │   │   └── use-visible.ts
│   │   │   ├── node-menu/
│   │   │   │   └── index.tsx
│   │   │   ├── node-panel/
│   │   │   │   ├── index.less
│   │   │   │   ├── index.tsx
│   │   │   │   ├── node-list.tsx
│   │   │   │   └── node-placeholder.tsx
│   │   │   ├── problem-panel/
│   │   │   │   ├── index.ts
│   │   │   │   ├── problem-panel.tsx
│   │   │   │   └── use-watch-validate.ts
│   │   │   ├── selector-box-popover/
│   │   │   │   └── index.tsx
│   │   │   ├── sidebar/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── node-form-panel.tsx
│   │   │   │   └── sidebar-node-renderer.tsx
│   │   │   ├── testrun/
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── use-fields.ts
│   │   │   │   │   ├── use-form-meta.ts
│   │   │   │   │   └── use-sync-default.ts
│   │   │   │   ├── json-value-editor/
│   │   │   │   │   └── index.tsx
│   │   │   │   ├── node-status-bar/
│   │   │   │   │   ├── group/
│   │   │   │   │   │   ├── index.module.less
│   │   │   │   │   │   └── index.tsx
│   │   │   │   │   ├── header/
│   │   │   │   │   │   ├── index.module.less
│   │   │   │   │   │   └── index.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── render/
│   │   │   │   │   │   ├── index.module.less
│   │   │   │   │   │   └── index.tsx
│   │   │   │   │   └── viewer/
│   │   │   │   │       ├── index.module.less
│   │   │   │   │       └── index.tsx
│   │   │   │   ├── testrun-button/
│   │   │   │   │   ├── index.module.less
│   │   │   │   │   └── index.tsx
│   │   │   │   ├── testrun-form/
│   │   │   │   │   ├── index.module.less
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── type.ts
│   │   │   │   ├── testrun-json-input/
│   │   │   │   │   ├── index.module.less
│   │   │   │   │   └── index.tsx
│   │   │   │   ├── testrun-panel/
│   │   │   │   │   ├── index.module.less
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── test-run-panel.tsx
│   │   │   │   └── trace-panel/
│   │   │   │       ├── index.module.less
│   │   │   │       └── index.tsx
│   │   │   └── tools/
│   │   │       ├── auto-layout.tsx
│   │   │       ├── comment.tsx
│   │   │       ├── download.tsx
│   │   │       ├── fit-view.tsx
│   │   │       ├── index.tsx
│   │   │       ├── interactive.tsx
│   │   │       ├── minimap-switch.tsx
│   │   │       ├── minimap.tsx
│   │   │       ├── mouse-pad-selector.less
│   │   │       ├── mouse-pad-selector.tsx
│   │   │       ├── readonly.tsx
│   │   │       ├── save.tsx
│   │   │       ├── styles.tsx
│   │   │       ├── switch-line.tsx
│   │   │       └── zoom-select.tsx
│   │   ├── context/
│   │   │   ├── index.ts
│   │   │   ├── node-render-context.ts
│   │   │   └── sidebar-context.ts
│   │   ├── data/
│   │   │   └── workflow-templates.ts
│   │   ├── editor.tsx
│   │   ├── form-components/
│   │   │   ├── feedback.tsx
│   │   │   ├── form-content/
│   │   │   │   ├── index.tsx
│   │   │   │   └── styles.tsx
│   │   │   ├── form-header/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── styles.tsx
│   │   │   │   ├── title-input.tsx
│   │   │   │   └── utils.tsx
│   │   │   ├── form-inputs/
│   │   │   │   ├── index.tsx
│   │   │   │   └── styles.tsx
│   │   │   ├── form-item/
│   │   │   │   ├── index.css
│   │   │   │   └── index.tsx
│   │   │   └── index.ts
│   │   ├── hooks/
│   │   │   ├── index.ts
│   │   │   ├── use-editor-props.tsx
│   │   │   ├── use-is-sidebar.ts
│   │   │   ├── use-node-render-context.ts
│   │   │   └── use-port-click.ts
│   │   ├── index.ts
│   │   ├── initial-data.ts
│   │   ├── nodes/
│   │   │   ├── block-end/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── block-start/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── break/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── code/
│   │   │   │   ├── components/
│   │   │   │   │   ├── code.tsx
│   │   │   │   │   ├── inputs.tsx
│   │   │   │   │   └── outputs.tsx
│   │   │   │   ├── form-meta.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   └── types.tsx
│   │   │   ├── comment/
│   │   │   │   └── index.tsx
│   │   │   ├── condition/
│   │   │   │   ├── condition-inputs/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styles.tsx
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── constants.ts
│   │   │   ├── continue/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── default-form-meta.tsx
│   │   │   ├── end/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── group/
│   │   │   │   └── index.tsx
│   │   │   ├── http/
│   │   │   │   ├── components/
│   │   │   │   │   ├── api.tsx
│   │   │   │   │   ├── body.tsx
│   │   │   │   │   ├── headers.tsx
│   │   │   │   │   ├── params.tsx
│   │   │   │   │   └── timeout.tsx
│   │   │   │   ├── form-meta.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   └── types.tsx
│   │   │   ├── index.ts
│   │   │   ├── knowledge/
│   │   │   │   └── index.tsx
│   │   │   ├── llm/
│   │   │   │   └── index.ts
│   │   │   ├── loop/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── start/
│   │   │   │   ├── form-meta.tsx
│   │   │   │   └── index.ts
│   │   │   ├── tool/
│   │   │   │   └── index.tsx
│   │   │   └── variable/
│   │   │       ├── form-meta.tsx
│   │   │       ├── index.tsx
│   │   │       ├── output-schema.ts
│   │   │       └── types.tsx
│   │   ├── plugins/
│   │   │   ├── context-menu-plugin/
│   │   │   │   ├── context-menu-layer.tsx
│   │   │   │   ├── context-menu-plugin.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.ts
│   │   │   ├── panel-manager-plugin/
│   │   │   │   ├── constants.ts
│   │   │   │   ├── hooks.ts
│   │   │   │   └── index.tsx
│   │   │   ├── runtime-plugin/
│   │   │   │   ├── client/
│   │   │   │   │   ├── base-client.ts
│   │   │   │   │   ├── browser-client/
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── server-client/
│   │   │   │   │       ├── constant.ts
│   │   │   │   │       ├── index.ts
│   │   │   │   │       └── type.ts
│   │   │   │   ├── create-runtime-plugin.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── runtime-service/
│   │   │   │   │   └── index.ts
│   │   │   │   ├── trace.ts
│   │   │   │   └── type.ts
│   │   │   └── variable-panel-plugin/
│   │   │       ├── components/
│   │   │       │   ├── full-variable-list.tsx
│   │   │       │   ├── global-variable-editor.tsx
│   │   │       │   ├── index.module.less
│   │   │       │   └── variable-panel.tsx
│   │   │       ├── index.ts
│   │   │       ├── variable-panel-layer.tsx
│   │   │       └── variable-panel-plugin.ts
│   │   ├── services/
│   │   │   ├── custom-service.ts
│   │   │   ├── index.ts
│   │   │   └── validate-service.ts
│   │   ├── shortcuts/
│   │   │   ├── collapse/
│   │   │   │   └── index.ts
│   │   │   ├── constants.ts
│   │   │   ├── copy/
│   │   │   │   └── index.ts
│   │   │   ├── delete/
│   │   │   │   └── index.ts
│   │   │   ├── expand/
│   │   │   │   └── index.ts
│   │   │   ├── index.ts
│   │   │   ├── paste/
│   │   │   │   ├── index.ts
│   │   │   │   ├── traverse.ts
│   │   │   │   └── unique-workflow.ts
│   │   │   ├── select-all/
│   │   │   │   └── index.ts
│   │   │   ├── shortcuts.ts
│   │   │   ├── type.ts
│   │   │   ├── zoom-in/
│   │   │   │   └── index.ts
│   │   │   └── zoom-out/
│   │   │       └── index.ts
│   │   ├── styles/
│   │   │   └── index.css
│   │   ├── type.d.ts
│   │   ├── typings/
│   │   │   ├── index.ts
│   │   │   ├── json-schema.ts
│   │   │   └── node.ts
│   │   ├── utils/
│   │   │   ├── backend-workflow.ts
│   │   │   ├── can-contain-node.ts
│   │   │   ├── index.ts
│   │   │   ├── on-drag-line-end.ts
│   │   │   └── toggle-loop-expanded.ts
│   │   └── workbench/
│   │       ├── runtime-hooks.ts
│   │       ├── workbench-shell.tsx
│   │       ├── workbench-sidebar.tsx
│   │       └── workbench-toolbar.tsx
│   └── tsconfig.json
├── ai4j-spring-boot-starter/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── github/
│       │   │           └── lnyocly/
│       │   │               └── ai4j/
│       │   │                   ├── AgentFlowProperties.java
│       │   │                   ├── AgentFlowRegistry.java
│       │   │                   ├── AiConfigAutoConfiguration.java
│       │   │                   ├── AiConfigProperties.java
│       │   │                   ├── AiPlatformProperties.java
│       │   │                   ├── BaichuanConfigProperties.java
│       │   │                   ├── DashScopeConfigProperties.java
│       │   │                   ├── DeepSeekConfigProperties.java
│       │   │                   ├── DoubaoConfigProperties.java
│       │   │                   ├── HunyuanConfigProperties.java
│       │   │                   ├── JinaConfigProperties.java
│       │   │                   ├── LingyiConfigProperties.java
│       │   │                   ├── MilvusConfigProperties.java
│       │   │                   ├── MinimaxConfigProperties.java
│       │   │                   ├── MoonshotConfigProperties.java
│       │   │                   ├── OkHttpConfigProperties.java
│       │   │                   ├── OllamaConfigProperties.java
│       │   │                   ├── OpenAiConfigProperties.java
│       │   │                   ├── PgVectorConfigProperties.java
│       │   │                   ├── PineconeConfigProperties.java
│       │   │                   ├── QdrantConfigProperties.java
│       │   │                   ├── SearXNGConfigProperties.java
│       │   │                   └── ZhipuConfigProperties.java
│       │   └── resources/
│       │       └── META-INF/
│       │           ├── spring/
│       │           │   └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│       │           └── spring.factories
│       └── test/
│           └── java/
│               └── io/
│                   └── github/
│                       └── lnyocly/
│                           └── ai4j/
│                               └── AgentFlowAutoConfigurationTest.java
├── docs-site/
│   ├── .gitignore
│   ├── README.md
│   ├── docusaurus.config.ts
│   ├── i18n/
│   │   └── zh-Hans/
│   │       ├── code.json
│   │       ├── docusaurus-plugin-content-docs/
│   │       │   ├── current/
│   │       │   │   ├── agent/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   ├── agent-teams.md
│   │       │   │   │   ├── codeact-custom-sandbox.md
│   │       │   │   │   ├── codeact-runtime.md
│   │       │   │   │   ├── coding-agent-cli.md
│   │       │   │   │   ├── coding-agent-command-reference.md
│   │       │   │   │   ├── custom-agent-development.md
│   │       │   │   │   ├── memory-management.md
│   │       │   │   │   ├── model-client-selection.md
│   │       │   │   │   ├── multi-provider-profiles.md
│   │       │   │   │   ├── overview.md
│   │       │   │   │   ├── provider-config-examples.md
│   │       │   │   │   ├── reference-core-classes.md
│   │       │   │   │   ├── runtime-implementations.md
│   │       │   │   │   ├── subagent-handoff-policy.md
│   │       │   │   │   ├── system-prompt-vs-instructions.md
│   │       │   │   │   ├── trace-observability.md
│   │       │   │   │   ├── weather-workflow-cookbook.md
│   │       │   │   │   └── workflow-stategraph.md
│   │       │   │   ├── ai-basics/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   ├── chat/
│   │       │   │   │   │   ├── _category_.json
│   │       │   │   │   │   ├── multimodal.md
│   │       │   │   │   │   ├── non-stream.md
│   │       │   │   │   │   ├── stream.md
│   │       │   │   │   │   └── tool-calling.md
│   │       │   │   │   ├── enhancements/
│   │       │   │   │   │   ├── _category_.json
│   │       │   │   │   │   ├── pinecone-rag-workflow.md
│   │       │   │   │   │   ├── searxng-enhancement.md
│   │       │   │   │   │   └── spi-http-stack.md
│   │       │   │   │   ├── overview.md
│   │       │   │   │   ├── platform-adaptation.md
│   │       │   │   │   ├── responses/
│   │       │   │   │   │   ├── _category_.json
│   │       │   │   │   │   ├── chat-vs-responses.md
│   │       │   │   │   │   ├── non-stream.md
│   │       │   │   │   │   └── stream-events.md
│   │       │   │   │   └── services/
│   │       │   │   │       ├── _category_.json
│   │       │   │   │       ├── audio.md
│   │       │   │   │       ├── embedding.md
│   │       │   │   │       ├── image-generation.md
│   │       │   │   │       └── realtime.md
│   │       │   │   ├── core-sdk/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   ├── agentflow-protocol-mapping.md
│   │       │   │   │   ├── agentflow.md
│   │       │   │   │   ├── audio.md
│   │       │   │   │   ├── chat/
│   │       │   │   │   │   ├── multimodal.md
│   │       │   │   │   │   ├── non-stream.md
│   │       │   │   │   │   ├── stream.md
│   │       │   │   │   │   └── tool-calling.md
│   │       │   │   │   ├── embedding.md
│   │       │   │   │   ├── image-generation.md
│   │       │   │   │   ├── overview.md
│   │       │   │   │   ├── pinecone-rag-workflow.md
│   │       │   │   │   ├── platform-service-matrix.md
│   │       │   │   │   ├── realtime.md
│   │       │   │   │   ├── responses/
│   │       │   │   │   │   ├── chat-vs-responses.md
│   │       │   │   │   │   ├── non-stream.md
│   │       │   │   │   │   └── stream-events.md
│   │       │   │   │   ├── searxng-enhancement.md
│   │       │   │   │   └── spi-http-stack.md
│   │       │   │   ├── deploy/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   └── cloudflare-pages.md
│   │       │   │   ├── getting-started/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   ├── chat-and-responses-guide.md
│   │       │   │   │   ├── coding-agent-cli-quickstart.md
│   │       │   │   │   ├── installation.md
│   │       │   │   │   ├── multimodal-and-function-call.md
│   │       │   │   │   ├── platforms-and-service-matrix.md
│   │       │   │   │   ├── quickstart-ollama.md
│   │       │   │   │   ├── quickstart-openai-jdk8.md
│   │       │   │   │   ├── quickstart-springboot.md
│   │       │   │   │   └── troubleshooting.md
│   │       │   │   ├── guides/
│   │       │   │   │   ├── _category_.json
│   │       │   │   │   ├── blog-migration-map.md
│   │       │   │   │   ├── deepseek-stream-search-rag.md
│   │       │   │   │   ├── pinecone-vector-workflow.md
│   │       │   │   │   ├── rag-legal-assistant.md
│   │       │   │   │   ├── searxng-web-search.md
│   │       │   │   │   └── spi-dispatcher-connectionpool.md
│   │       │   │   ├── intro.md
│   │       │   │   └── mcp/
│   │       │   │       ├── _category_.json
│   │       │   │       ├── build-your-mcp-server.md
│   │       │   │       ├── client-integration.md
│   │       │   │       ├── gateway-management.md
│   │       │   │       ├── mcp-agent-end-to-end.md
│   │       │   │       ├── mysql-dynamic-datasource.md
│   │       │   │       ├── overview.md
│   │       │   │       ├── third-party-mcp-integration.md
│   │       │   │       ├── tool-exposure-semantics.md
│   │       │   │       └── transport-types.md
│   │       │   └── current.json
│   │       └── docusaurus-theme-classic/
│   │           ├── footer.json
│   │           └── navbar.json
│   ├── package.json
│   ├── scripts/
│   │   └── generate_agent_teams_api_docs.py
│   ├── sidebars.ts
│   ├── src/
│   │   ├── components/
│   │   │   └── HomepageFeatures/
│   │   │       ├── index.tsx
│   │   │       └── styles.module.css
│   │   ├── css/
│   │   │   └── custom.css
│   │   ├── pages/
│   │   │   ├── index.module.css
│   │   │   └── index.tsx
│   │   └── theme/
│   │       └── NotFound/
│   │           └── Content/
│   │               └── index.tsx
│   ├── static/
│   │   ├── .nojekyll
│   │   ├── install.ps1
│   │   └── install.sh
│   └── tsconfig.json
└── pom.xml
Download .txt
Showing preview only (806K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (8443 symbols across 1010 files)

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/Agent.java
  class Agent (line 8) | public class Agent {
    method Agent (line 14) | public Agent(AgentRuntime runtime, AgentContext baseContext, Supplier<...
    method run (line 20) | public AgentResult run(AgentRequest request) throws Exception {
    method runStream (line 24) | public void runStream(AgentRequest request, AgentListener listener) th...
    method runStreamResult (line 28) | public AgentResult runStreamResult(AgentRequest request, AgentListener...
    method newSession (line 32) | public AgentSession newSession() {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/AgentBuilder.java
  class AgentBuilder (line 34) | public class AgentBuilder {
    method runtime (line 63) | public AgentBuilder runtime(AgentRuntime runtime) {
    method modelClient (line 68) | public AgentBuilder modelClient(AgentModelClient modelClient) {
    method toolRegistry (line 73) | public AgentBuilder toolRegistry(AgentToolRegistry toolRegistry) {
    method toolRegistry (line 78) | public AgentBuilder toolRegistry(List<String> functions, List<String> ...
    method subAgentRegistry (line 83) | public AgentBuilder subAgentRegistry(SubAgentRegistry subAgentRegistry) {
    method handoffPolicy (line 88) | public AgentBuilder handoffPolicy(HandoffPolicy handoffPolicy) {
    method subAgent (line 93) | public AgentBuilder subAgent(SubAgentDefinition definition) {
    method subAgents (line 100) | public AgentBuilder subAgents(List<SubAgentDefinition> definitions) {
    method toolExecutor (line 107) | public AgentBuilder toolExecutor(ToolExecutor toolExecutor) {
    method codeExecutor (line 112) | public AgentBuilder codeExecutor(CodeExecutor codeExecutor) {
    method memorySupplier (line 117) | public AgentBuilder memorySupplier(Supplier<AgentMemory> memorySupplie...
    method options (line 122) | public AgentBuilder options(AgentOptions options) {
    method codeActOptions (line 127) | public AgentBuilder codeActOptions(CodeActOptions codeActOptions) {
    method traceExporter (line 132) | public AgentBuilder traceExporter(TraceExporter traceExporter) {
    method traceConfig (line 137) | public AgentBuilder traceConfig(TraceConfig traceConfig) {
    method eventPublisher (line 142) | public AgentBuilder eventPublisher(AgentEventPublisher eventPublisher) {
    method model (line 147) | public AgentBuilder model(String model) {
    method instructions (line 152) | public AgentBuilder instructions(String instructions) {
    method systemPrompt (line 157) | public AgentBuilder systemPrompt(String systemPrompt) {
    method temperature (line 162) | public AgentBuilder temperature(Double temperature) {
    method topP (line 167) | public AgentBuilder topP(Double topP) {
    method maxOutputTokens (line 172) | public AgentBuilder maxOutputTokens(Integer maxOutputTokens) {
    method reasoning (line 177) | public AgentBuilder reasoning(Object reasoning) {
    method toolChoice (line 182) | public AgentBuilder toolChoice(Object toolChoice) {
    method parallelToolCalls (line 187) | public AgentBuilder parallelToolCalls(Boolean parallelToolCalls) {
    method store (line 192) | public AgentBuilder store(Boolean store) {
    method user (line 197) | public AgentBuilder user(String user) {
    method extraBody (line 202) | public AgentBuilder extraBody(Map<String, Object> extraBody) {
    method build (line 207) | public Agent build() {
    method createDefaultCodeExecutor (line 264) | private CodeExecutor createDefaultCodeExecutor() {
    method resolveSubAgentRegistry (line 271) | private SubAgentRegistry resolveSubAgentRegistry() {
    method resolveToolRegistry (line 281) | private AgentToolRegistry resolveToolRegistry(AgentToolRegistry baseTo...
    method resolveToolNames (line 288) | private Set<String> resolveToolNames(AgentToolRegistry registry) {
    method createToolUtilRegistry (line 308) | private AgentToolRegistry createToolUtilRegistry(List<String> function...
    method createToolUtilExecutor (line 320) | private ToolExecutor createToolUtilExecutor(Set<String> allowedToolNam...
    method instantiateClass (line 338) | private Object instantiateClass(String className, Class<?>[] parameter...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/AgentContext.java
  class AgentContext (line 15) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/AgentOptions.java
  class AgentOptions (line 7) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/AgentRequest.java
  class AgentRequest (line 10) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/AgentResult.java
  class AgentResult (line 12) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/AgentRuntime.java
  type AgentRuntime (line 5) | public interface AgentRuntime {
    method run (line 7) | AgentResult run(AgentContext context, AgentRequest request) throws Exc...
    method runStream (line 9) | void runStream(AgentContext context, AgentRequest request, AgentListen...
    method runStreamResult (line 11) | default AgentResult runStreamResult(AgentContext context, AgentRequest...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/AgentSession.java
  class AgentSession (line 5) | public class AgentSession {
    method AgentSession (line 10) | public AgentSession(AgentRuntime runtime, AgentContext context) {
    method run (line 15) | public AgentResult run(String input) throws Exception {
    method run (line 19) | public AgentResult run(AgentRequest request) throws Exception {
    method runStream (line 23) | public void runStream(AgentRequest request, AgentListener listener) th...
    method runStreamResult (line 27) | public AgentResult runStreamResult(AgentRequest request, AgentListener...
    method getContext (line 31) | public AgentContext getContext() {
    method getRuntime (line 35) | public AgentRuntime getRuntime() {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/Agents.java
  class Agents (line 9) | public final class Agents {
    method Agents (line 11) | private Agents() {
    method builder (line 14) | public static AgentBuilder builder() {
    method react (line 18) | public static AgentBuilder react() {
    method codeAct (line 22) | public static AgentBuilder codeAct() {
    method deepResearch (line 26) | public static AgentBuilder deepResearch() {
    method team (line 30) | public static AgentTeamBuilder team() {
    method teamAgent (line 34) | public static Agent teamAgent(AgentTeamBuilder builder) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/codeact/CodeActOptions.java
  class CodeActOptions (line 6) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/codeact/CodeExecutionRequest.java
  class CodeExecutionRequest (line 9) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/codeact/CodeExecutionResult.java
  class CodeExecutionResult (line 6) | @Data
    method isSuccess (line 16) | public boolean isSuccess() {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/codeact/CodeExecutor.java
  type CodeExecutor (line 3) | public interface CodeExecutor {
    method execute (line 5) | CodeExecutionResult execute(CodeExecutionRequest request) throws Excep...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/codeact/GraalVmCodeExecutor.java
  class GraalVmCodeExecutor (line 29) | public class GraalVmCodeExecutor implements CodeExecutor {
    method GraalVmCodeExecutor (line 35) | public GraalVmCodeExecutor() {
    method GraalVmCodeExecutor (line 39) | public GraalVmCodeExecutor(String ignored) {
    method execute (line 42) | @Override
    method normalizeLanguage (line 64) | private String normalizeLanguage(String language) {
    method buildPythonPrelude (line 75) | private String buildPythonPrelude(List<String> toolNames) {
    method wrapPythonCode (line 106) | private String wrapPythonCode(String code) {
    method escapePython (line 124) | private String escapePython(String text) {
    method trimError (line 128) | private String trimError(String error) {
    method executePythonWithGraalPy (line 135) | private CodeExecutionResult executePythonWithGraalPy(CodeExecutionRequ...
    method resolveValue (line 251) | private String resolveValue(Value value) {
    method isUndefined (line 264) | private boolean isUndefined(Value value) {
    method filterPolyglotWarnings (line 276) | private String filterPolyglotWarnings(String stderr) {
    class ToolBridge (line 307) | private static class ToolBridge {
      method ToolBridge (line 311) | private ToolBridge(ToolExecutor toolExecutor, String user) {
      method call (line 316) | @HostAccess.Export
      method resolveName (line 336) | private String resolveName(String name) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/codeact/NashornCodeExecutor.java
  class NashornCodeExecutor (line 24) | public class NashornCodeExecutor implements CodeExecutor {
    method execute (line 30) | @Override
    method normalizeLanguage (line 46) | private String normalizeLanguage(String language) {
    method executeJavaScript (line 57) | private CodeExecutionResult executeJavaScript(CodeExecutionRequest req...
    method buildPrelude (line 122) | private String buildPrelude(List<String> toolNames) {
    method wrapCode (line 166) | private String wrapCode(String code) {
    method escapeJs (line 178) | private String escapeJs(String text) {
    method trimError (line 182) | private String trimError(String error) {
    class ToolBridge (line 189) | public static class ToolBridge {
      method ToolBridge (line 193) | private ToolBridge(ToolExecutor toolExecutor, String user) {
      method call (line 198) | public String call(String name, String arguments) throws Exception {
      method resolveName (line 210) | private String resolveName(String name) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/event/AgentEvent.java
  class AgentEvent (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/event/AgentEventPublisher.java
  class AgentEventPublisher (line 6) | public class AgentEventPublisher {
    method AgentEventPublisher (line 10) | public AgentEventPublisher() {
    method AgentEventPublisher (line 13) | public AgentEventPublisher(List<AgentListener> initial) {
    method addListener (line 19) | public void addListener(AgentListener listener) {
    method publish (line 25) | public void publish(AgentEvent event) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/event/AgentEventType.java
  type AgentEventType (line 3) | public enum AgentEventType {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/event/AgentListener.java
  type AgentListener (line 3) | public interface AgentListener {
    method onEvent (line 5) | void onEvent(AgentEvent event);

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/Ai4jFlowGramLlmNodeRunner.java
  class Ai4jFlowGramLlmNodeRunner (line 22) | public class Ai4jFlowGramLlmNodeRunner implements FlowGramLlmNodeRunner {
    method Ai4jFlowGramLlmNodeRunner (line 30) | public Ai4jFlowGramLlmNodeRunner(AgentModelClient modelClient) {
    method Ai4jFlowGramLlmNodeRunner (line 34) | public Ai4jFlowGramLlmNodeRunner(ModelClientResolver modelClientResolv...
    method Ai4jFlowGramLlmNodeRunner (line 38) | public Ai4jFlowGramLlmNodeRunner(ModelClientResolver modelClientResolver,
    method Ai4jFlowGramLlmNodeRunner (line 43) | public Ai4jFlowGramLlmNodeRunner(AgentModelClient modelClient,
    method Ai4jFlowGramLlmNodeRunner (line 49) | public Ai4jFlowGramLlmNodeRunner(AgentModelClient modelClient,
    method Ai4jFlowGramLlmNodeRunner (line 56) | public Ai4jFlowGramLlmNodeRunner(AgentModelClient modelClient,
    method run (line 68) | @Override
    method buildMetrics (line 116) | private Map<String, Object> buildMetrics(String model, long durationMi...
    method tokenValue (line 165) | private Long tokenValue(Object usage, String camelName, String snakeNa...
    method resolveModelClient (line 173) | private AgentModelClient resolveModelClient(FlowGramNodeSchema node, M...
    method defaultOptions (line 183) | private static AgentOptions defaultOptions() {
    method safeNodeId (line 190) | private String safeNodeId(FlowGramNodeSchema node) {
    method valueAsString (line 194) | private static String valueAsString(Object value) {
    method valueAsDouble (line 198) | private static Double valueAsDouble(Object value) {
    method valueAsInteger (line 216) | private static Integer valueAsInteger(Object value) {
    method firstNonBlank (line 234) | private static String firstNonBlank(String... values) {
    method isBlank (line 246) | private static boolean isBlank(String value) {
    method mapValue (line 250) | @SuppressWarnings("unchecked")
    method firstNonNull (line 263) | private static Object firstNonNull(Object... values) {
    method propertyValue (line 275) | @SuppressWarnings("unchecked")
    method normalizedSource (line 295) | private static Object normalizedSource(Object source) {
    method normalizeTree (line 307) | @SuppressWarnings("unchecked")
    method invokeAccessor (line 332) | private static Object invokeAccessor(Object source, String methodName) {
    method fieldValue (line 356) | private static Object fieldValue(Object source, String name) {
    method longObject (line 373) | private static Long longObject(Object value) {
    type ModelClientResolver (line 387) | public interface ModelClientResolver {
      method resolve (line 388) | AgentModelClient resolve(FlowGramNodeSchema node, Map<String, Object...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/FlowGramLlmNodeRunner.java
  type FlowGramLlmNodeRunner (line 7) | public interface FlowGramLlmNodeRunner {
    method run (line 9) | Map<String, Object> run(FlowGramNodeSchema node, Map<String, Object> i...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/FlowGramNodeExecutionContext.java
  class FlowGramNodeExecutionContext (line 11) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/FlowGramNodeExecutionResult.java
  class FlowGramNodeExecutionResult (line 10) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/FlowGramNodeExecutor.java
  type FlowGramNodeExecutor (line 3) | public interface FlowGramNodeExecutor {
    method getType (line 5) | String getType();
    method execute (line 7) | FlowGramNodeExecutionResult execute(FlowGramNodeExecutionContext conte...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/FlowGramRuntimeEvent.java
  class FlowGramRuntimeEvent (line 8) | @Data
    type Type (line 21) | public enum Type {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/FlowGramRuntimeListener.java
  type FlowGramRuntimeListener (line 3) | public interface FlowGramRuntimeListener {
    method onEvent (line 5) | void onEvent(FlowGramRuntimeEvent event);

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/FlowGramRuntimeService.java
  class FlowGramRuntimeService (line 33) | public class FlowGramRuntimeService implements AutoCloseable {
    method FlowGramRuntimeService (line 55) | public FlowGramRuntimeService(FlowGramLlmNodeRunner llmNodeRunner) {
    method FlowGramRuntimeService (line 59) | public FlowGramRuntimeService(FlowGramLlmNodeRunner llmNodeRunner, Exe...
    method FlowGramRuntimeService (line 63) | private FlowGramRuntimeService(FlowGramLlmNodeRunner llmNodeRunner,
    method registerNodeExecutor (line 71) | public FlowGramRuntimeService registerNodeExecutor(FlowGramNodeExecuto...
    method registerListener (line 79) | public FlowGramRuntimeService registerListener(FlowGramRuntimeListener...
    method runTask (line 87) | public FlowGramTaskRunOutput runTask(FlowGramTaskRunInput input) {
    method validateTask (line 101) | public FlowGramTaskValidateOutput validateTask(FlowGramTaskRunInput in...
    method getTaskReport (line 109) | public FlowGramTaskReportOutput getTaskReport(String taskId) {
    method getTaskResult (line 114) | public FlowGramTaskResultOutput getTaskResult(String taskId) {
    method cancelTask (line 119) | public FlowGramTaskCancelOutput cancelTask(String taskId) {
    method close (line 132) | @Override
    method executeTask (line 139) | private void executeTask(TaskRecord record, FlowGramNodeSchema startNo...
    method executeFromNode (line 166) | private Map<String, Object> executeFromNode(TaskRecord record,
    method executeNode (line 195) | private Map<String, Object> executeNode(TaskRecord record,
    method publishTaskEvent (line 245) | private void publishTaskEvent(TaskRecord record,
    method publishNodeEvent (line 261) | private void publishNodeEvent(TaskRecord record,
    method publishEvent (line 279) | private void publishEvent(FlowGramRuntimeEvent event) {
    method executeStartNode (line 295) | private Map<String, Object> executeStartNode(TaskRecord record, FlowGr...
    method executeEndNode (line 303) | private Map<String, Object> executeEndNode(TaskRecord record,
    method executeLlmNode (line 318) | private Map<String, Object> executeLlmNode(TaskRecord record,
    method executeConditionNode (line 334) | private Map<String, Object> executeConditionNode(TaskRecord record,
    method executeLoopNode (line 348) | private Map<String, Object> executeLoopNode(TaskRecord record,
    method executeCustomNode (line 402) | private Map<String, Object> executeCustomNode(TaskRecord record,
    method selectNextEdges (line 422) | private List<FlowGramEdgeSchema> selectNextEdges(TaskRecord record,
    method resolveConditionBranch (line 450) | private String resolveConditionBranch(TaskRecord record,
    method conditionMatches (line 486) | private boolean conditionMatches(Map<String, Object> rule,
    method evaluateConditionOperand (line 508) | private Object evaluateConditionOperand(Object operand,
    method compareCondition (line 525) | private boolean compareCondition(Object left, String operator, Object ...
    method resolveInputs (line 573) | private Map<String, Object> resolveInputs(TaskRecord record,
    method evaluateValue (line 586) | private Object evaluateValue(Object value, TaskRecord record, Map<Stri...
    method resolveReference (line 610) | private Object resolveReference(Object content, TaskRecord record, Map...
    method resolveRootReference (line 625) | private Object resolveRootReference(Object segment, TaskRecord record,...
    method evaluateExpression (line 639) | private Object evaluateExpression(String expression, TaskRecord record...
    method renderTemplate (line 660) | private String renderTemplate(String template, TaskRecord record, Map<...
    method replaceTemplatePattern (line 670) | private String replaceTemplatePattern(String template,
    method resolvePathExpression (line 692) | private Object resolvePathExpression(String expression, TaskRecord rec...
    method descend (line 706) | private Object descend(Object current, Object segment) {
    method parseAndValidate (line 726) | private ParsedTask parseAndValidate(FlowGramTaskRunInput input) {
    method validateInternal (line 737) | private List<String> validateInternal(FlowGramTaskRunInput input) {
    method parseSchema (line 759) | private FlowGramWorkflowSchema parseSchema(FlowGramTaskRunInput input) {
    method parseSchema (line 768) | private FlowGramWorkflowSchema parseSchema(FlowGramTaskRunInput input,...
    method validateGraph (line 786) | private void validateGraph(String graphName,
    method validateNodeDefinitions (line 839) | private void validateNodeDefinitions(List<FlowGramNodeSchema> nodes,
    method validateRequiredInputBindings (line 855) | private void validateRequiredInputBindings(FlowGramNodeSchema node, Li...
    method validateOutputRefs (line 872) | private void validateOutputRefs(FlowGramNodeSchema node,
    method validateRefValue (line 884) | private void validateRefValue(FlowGramNodeSchema node,
    method collectNodes (line 905) | private void collectNodes(List<FlowGramNodeSchema> nodes,
    method findSingleStart (line 928) | private FlowGramNodeSchema findSingleStart(Iterable<FlowGramNodeSchema...
    method isSupportedType (line 945) | private boolean isSupportedType(String type) {
    method checkCanceled (line 956) | private void checkCanceled(TaskRecord record) throws InterruptedExcept...
    method createExecutor (line 962) | private static ExecutorService createExecutor() {
    method applyObjectDefaults (line 974) | private Map<String, Object> applyObjectDefaults(Map<String, Object> sc...
    method validateObjectSchema (line 995) | private void validateObjectSchema(String label, Map<String, Object> sc...
    method collectObjectSchemaErrors (line 1003) | private void collectObjectSchemaErrors(String label,
    method collectPropertyErrors (line 1031) | private void collectPropertyErrors(String label,
    method matchesType (line 1066) | private boolean matchesType(String type, Object value) {
    method propertyDefault (line 1092) | private Object propertyDefault(Map<String, Object> objectSchema, Strin...
    method schemaMap (line 1098) | private Map<String, Object> schemaMap(FlowGramNodeSchema node, String ...
    method dataValue (line 1102) | private Object dataValue(FlowGramNodeSchema node, String key) {
    method safeMap (line 1106) | private static Map<String, Object> safeMap(Map<String, Object> value) {
    method copyMap (line 1117) | private static Map<String, Object> copyMap(Map<String, ?> value) {
    method copyValue (line 1128) | @SuppressWarnings("unchecked")
    method mapValue (line 1148) | @SuppressWarnings("unchecked")
    method objectList (line 1161) | @SuppressWarnings("unchecked")
    method stringList (line 1169) | @SuppressWarnings("unchecked")
    method normalizeType (line 1183) | private static String normalizeType(String value) {
    method normalizeOperator (line 1187) | private static String normalizeOperator(String value) {
    method safeNodeId (line 1199) | private static String safeNodeId(FlowGramNodeSchema node) {
    method safeMessage (line 1203) | private static String safeMessage(Throwable throwable) {
    method firstNonNull (line 1210) | private static Object firstNonNull(Object... values) {
    method firstNonBlank (line 1222) | private static String firstNonBlank(String... values) {
    method valuesEqual (line 1234) | private static boolean valuesEqual(Object left, Object right) {
    method truthy (line 1238) | private static boolean truthy(Object value) {
    method valueAsString (line 1260) | private static String valueAsString(Object value) {
    method valueAsDouble (line 1264) | private static Double valueAsDouble(Object value) {
    method valueAsInteger (line 1282) | private static Integer valueAsInteger(Object value) {
    method isBlank (line 1300) | private static boolean isBlank(String value) {
    method actualType (line 1304) | private static String actualType(Object value) {
    method resolveInputValue (line 1329) | private static Object resolveInputValue(Map<String, Object> inputs, St...
    class ParsedTask (line 1333) | private static final class ParsedTask {
      method ParsedTask (line 1338) | private ParsedTask(FlowGramWorkflowSchema schema,
    class GraphSegment (line 1347) | private static final class GraphSegment {
      method GraphSegment (line 1352) | private GraphSegment(Map<String, FlowGramNodeSchema> nodes,
      method root (line 1360) | private static GraphSegment root(FlowGramWorkflowSchema schema) {
      method loop (line 1364) | private static GraphSegment loop(FlowGramNodeSchema node) {
      method getNode (line 1368) | private FlowGramNodeSchema getNode(String nodeId) {
      method outgoing (line 1372) | private List<FlowGramEdgeSchema> outgoing(String nodeId) {
      method entryNodeIds (line 1377) | private List<String> entryNodeIds() {
      method isEmpty (line 1401) | private boolean isEmpty() {
      method isTerminalResultGraph (line 1405) | private boolean isTerminalResultGraph() {
      method indexNodes (line 1409) | private static Map<String, FlowGramNodeSchema> indexNodes(List<FlowG...
      method indexOutgoing (line 1423) | private static Map<String, List<FlowGramEdgeSchema>> indexOutgoing(L...
    class TaskRecord (line 1443) | private static final class TaskRecord {
      method TaskRecord (line 1464) | private TaskRecord(String taskId,
      method updateNode (line 1479) | private void updateNode(String nodeId, String status, String error, ...
      method recordNodeInputs (line 1501) | private void recordNodeInputs(String nodeId, Map<String, Object> inp...
      method recordNodeOutputs (line 1505) | private void recordNodeOutputs(String nodeId, Map<String, Object> ou...
      method updateWorkflow (line 1509) | private void updateWorkflow(String status, boolean terminated, Strin...
      method toReport (line 1525) | private FlowGramTaskReportOutput toReport() {
      method toResult (line 1549) | private FlowGramTaskResultOutput toResult() {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/model/FlowGramEdgeSchema.java
  class FlowGramEdgeSchema (line 8) | @Data
    method sourcePortKey (line 21) | public String sourcePortKey() {
    method firstNonBlank (line 25) | private String firstNonBlank(String... values) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/model/FlowGramNodeSchema.java
  class FlowGramNodeSchema (line 11) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/model/FlowGramTaskCancelOutput.java
  class FlowGramTaskCancelOutput (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/model/FlowGramTaskReportOutput.java
  class FlowGramTaskReportOutput (line 10) | @Data
    class WorkflowStatus (line 21) | @Data
    class NodeStatus (line 33) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/model/FlowGramTaskResultOutput.java
  class FlowGramTaskResultOutput (line 10) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/model/FlowGramTaskRunInput.java
  class FlowGramTaskRunInput (line 10) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/model/FlowGramTaskRunOutput.java
  class FlowGramTaskRunOutput (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/model/FlowGramTaskValidateOutput.java
  class FlowGramTaskValidateOutput (line 10) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/flowgram/model/FlowGramWorkflowSchema.java
  class FlowGramWorkflowSchema (line 10) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/memory/AgentMemory.java
  type AgentMemory (line 5) | public interface AgentMemory {
    method addUserInput (line 7) | void addUserInput(Object input);
    method addOutputItems (line 9) | void addOutputItems(List<Object> items);
    method addToolOutput (line 11) | void addToolOutput(String callId, String output);
    method getItems (line 13) | List<Object> getItems();
    method getSummary (line 15) | String getSummary();
    method clear (line 17) | void clear();

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/memory/InMemoryAgentMemory.java
  class InMemoryAgentMemory (line 9) | public class InMemoryAgentMemory implements AgentMemory {
    method InMemoryAgentMemory (line 15) | public InMemoryAgentMemory() {
    method InMemoryAgentMemory (line 18) | public InMemoryAgentMemory(MemoryCompressor compressor) {
    method setCompressor (line 22) | public void setCompressor(MemoryCompressor compressor) {
    method addUserInput (line 26) | @Override
    method addOutputItems (line 39) | @Override
    method addToolOutput (line 48) | @Override
    method getItems (line 57) | @Override
    method getSummary (line 68) | @Override
    method setSummary (line 73) | public void setSummary(String summary) {
    method snapshot (line 77) | public MemorySnapshot snapshot() {
    method restore (line 81) | public void restore(MemorySnapshot snapshot) {
    method clear (line 89) | @Override
    method maybeCompress (line 95) | private void maybeCompress() {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/memory/JdbcAgentMemory.java
  class JdbcAgentMemory (line 16) | public class JdbcAgentMemory implements AgentMemory {
    method JdbcAgentMemory (line 30) | public JdbcAgentMemory(JdbcAgentMemoryConfig config) {
    method JdbcAgentMemory (line 49) | public JdbcAgentMemory(String jdbcUrl, String sessionId) {
    method JdbcAgentMemory (line 56) | public JdbcAgentMemory(String jdbcUrl, String username, String passwor...
    method JdbcAgentMemory (line 65) | public JdbcAgentMemory(DataSource dataSource, String sessionId) {
    method setCompressor (line 72) | public void setCompressor(MemoryCompressor compressor) {
    method setSummary (line 79) | public synchronized void setSummary(String summary) {
    method snapshot (line 85) | public synchronized MemorySnapshot snapshot() {
    method restore (line 90) | public synchronized void restore(MemorySnapshot snapshot) {
    method addUserInput (line 97) | @Override
    method addOutputItems (line 112) | @Override
    method addToolOutput (line 123) | @Override
    method getItems (line 134) | @Override
    method getSummary (line 147) | @Override
    method clear (line 152) | @Override
    method initializeSchema (line 157) | private void initializeSchema() {
    method loadSnapshot (line 174) | private MemorySnapshot loadSnapshot() {
    method replaceSnapshot (line 208) | private void replaceSnapshot(MemorySnapshot snapshot) {
    method applyCompressor (line 256) | private MemorySnapshot applyCompressor(MemorySnapshot snapshot) {
    method copyItems (line 265) | private List<Object> copyItems(List<Object> items) {
    method openConnection (line 269) | private Connection openConnection() throws Exception {
    method validIdentifier (line 279) | private String validIdentifier(String value) {
    method requiredText (line 287) | private String requiredText(String value, String fieldName) {
    method trimToNull (line 295) | private String trimToNull(String value) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/memory/JdbcAgentMemoryConfig.java
  class JdbcAgentMemoryConfig (line 10) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/memory/MemoryCompressor.java
  type MemoryCompressor (line 3) | public interface MemoryCompressor {
    method compress (line 5) | MemorySnapshot compress(MemorySnapshot snapshot);

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/memory/MemorySnapshot.java
  class MemorySnapshot (line 11) | @Data
    method from (line 21) | public static MemorySnapshot from(List<Object> items, String summary) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/memory/WindowedMemoryCompressor.java
  class WindowedMemoryCompressor (line 7) | public class WindowedMemoryCompressor implements MemoryCompressor {
    method WindowedMemoryCompressor (line 11) | public WindowedMemoryCompressor(int maxItems) {
    method compress (line 18) | @Override

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/model/AgentModelClient.java
  type AgentModelClient (line 7) | public interface AgentModelClient {
    method create (line 9) | AgentModelResult create(AgentPrompt prompt) throws Exception;
    method createStream (line 11) | AgentModelResult createStream(AgentPrompt prompt, AgentModelStreamList...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/model/AgentModelResult.java
  class AgentModelResult (line 11) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/model/AgentModelStreamListener.java
  type AgentModelStreamListener (line 5) | public interface AgentModelStreamListener {
    method onReasoningDelta (line 7) | default void onReasoningDelta(String delta) {
    method onDeltaText (line 10) | default void onDeltaText(String delta) {
    method onToolCall (line 13) | default void onToolCall(AgentToolCall call) {
    method onEvent (line 16) | default void onEvent(Object event) {
    method onComplete (line 19) | default void onComplete(AgentModelResult result) {
    method onError (line 22) | default void onError(Throwable t) {
    method onRetry (line 25) | default void onRetry(String message, int attempt, int maxAttempts, Thr...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/model/AgentPrompt.java
  class AgentPrompt (line 12) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/model/ChatModelClient.java
  class ChatModelClient (line 21) | public class ChatModelClient implements AgentModelClient {
    method ChatModelClient (line 29) | public ChatModelClient(IChatService chatService) {
    method ChatModelClient (line 33) | public ChatModelClient(IChatService chatService, String baseUrl, Strin...
    method create (line 39) | @Override
    method createStream (line 46) | @Override
    method cancelActiveStream (line 77) | public static void cancelActiveStream(Thread thread) {
    method throwIfInterrupted (line 87) | private void throwIfInterrupted(SseListener sseListener) throws Interr...
    method toChatCompletion (line 95) | private ChatCompletion toChatCompletion(AgentPrompt prompt, boolean st...
    method convertTools (line 148) | private List<Tool> convertTools(List<Object> tools) {
    method convertToMessage (line 161) | private ChatMessage convertToMessage(Object item) {
    method convertMessageToolCalls (line 203) | private List<ToolCall> convertMessageToolCalls(Object value) {
    method buildMessageFromContent (line 238) | private ChatMessage buildMessageFromContent(String role, Object conten...
    method extractImageUrl (line 293) | private String extractImageUrl(Object imageUrl) {
    method valueAsString (line 308) | private String valueAsString(Object value) {
    method toModelResult (line 312) | private AgentModelResult toModelResult(ChatCompletionResponse response) {
    class StreamingSseListener (line 351) | private final class StreamingSseListener extends SseListener {
      method StreamingSseListener (line 355) | private StreamingSseListener(AgentModelStreamListener listener) {
      method error (line 359) | @Override
      method send (line 366) | @Override
      method retry (line 382) | @Override
      method toResult (line 393) | private AgentModelResult toResult() {
    method buildAssistantMemoryItems (line 417) | private List<Object> buildAssistantMemoryItems(String outputText, List...
    method convertToolCalls (line 432) | private List<AgentToolCall> convertToolCalls(List<ToolCall> toolCalls) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/model/ResponsesModelClient.java
  class ResponsesModelClient (line 17) | public class ResponsesModelClient implements AgentModelClient {
    method ResponsesModelClient (line 26) | public ResponsesModelClient(IResponsesService responsesService) {
    method ResponsesModelClient (line 30) | public ResponsesModelClient(IResponsesService responsesService, String...
    method create (line 36) | @Override
    method createStream (line 43) | @Override
    method cancelActiveStream (line 99) | public static void cancelActiveStream(Thread thread) {
    method throwIfInterrupted (line 109) | private void throwIfInterrupted(ResponseSseListener sseListener) throw...
    method toResponseRequest (line 117) | private ResponseRequest toResponseRequest(AgentPrompt prompt, boolean ...
    method toModelResult (line 152) | private AgentModelResult toModelResult(Response response) {
    method buildItems (line 166) | private List<Object> buildItems(AgentPrompt prompt) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/runtime/AgentToolExecutionScope.java
  class AgentToolExecutionScope (line 5) | public final class AgentToolExecutionScope {
    type EventEmitter (line 7) | public interface EventEmitter {
      method emit (line 9) | void emit(AgentEventType type, String message, Object payload);
    type ScopeCallable (line 12) | public interface ScopeCallable<T> {
      method call (line 14) | T call() throws Exception;
    method AgentToolExecutionScope (line 19) | private AgentToolExecutionScope() {
    method runWithEmitter (line 22) | public static <T> T runWithEmitter(EventEmitter emitter, ScopeCallable...
    method emit (line 43) | public static void emit(AgentEventType type, String message, Object pa...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/runtime/BaseAgentRuntime.java
  class BaseAgentRuntime (line 31) | public abstract class BaseAgentRuntime implements io.github.lnyocly.ai4j...
    method runtimeName (line 33) | protected String runtimeName() {
    method runtimeInstructions (line 37) | protected String runtimeInstructions() {
    method run (line 41) | @Override
    method runStream (line 46) | @Override
    method runStreamResult (line 51) | @Override
    method runInternal (line 56) | protected AgentResult runInternal(AgentContext context, AgentRequest r...
    method throwIfInterrupted (line 157) | private void throwIfInterrupted() throws InterruptedException {
    method normalizeToolCalls (line 163) | private List<AgentToolCall> normalizeToolCalls(List<AgentToolCall> cal...
    method buildPrompt (line 189) | protected AgentPrompt buildPrompt(AgentContext context, AgentMemory me...
    method executeModel (line 218) | protected AgentModelResult executeModel(AgentContext context, AgentPro...
    method retryPayload (line 284) | private Map<String, Object> retryPayload(int attempt, int maxAttempts,...
    method executeTool (line 294) | protected String executeTool(AgentContext context, AgentToolCall call)...
    method executeTool (line 298) | protected String executeTool(AgentContext context,
    method buildToolErrorOutput (line 326) | protected String buildToolErrorOutput(AgentToolCall call, Exception er...
    method buildToolValidationErrorOutput (line 338) | protected String buildToolValidationErrorOutput(AgentToolCall call, St...
    method safeToolErrorMessage (line 342) | private String safeToolErrorMessage(Exception error) {
    method trimToNull (line 349) | private String trimToNull(String value) {
    method executeToolCallsSequential (line 357) | private List<String> executeToolCallsSequential(AgentContext context,
    method executeToolCallsInParallel (line 368) | private List<String> executeToolCallsInParallel(AgentContext context,
    method waitForFuture (line 388) | private String waitForFuture(Future<String> future) throws Exception {
    method publish (line 403) | protected void publish(AgentContext context, AgentListener listener, A...
    method mergeText (line 419) | private String mergeText(String base, String extra) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/runtime/CodeActRuntime.java
  class CodeActRuntime (line 27) | public class CodeActRuntime extends BaseAgentRuntime {
    method runtimeName (line 31) | @Override
    method run (line 36) | @Override
    method runStream (line 41) | @Override
    method runInternal (line 46) | protected AgentResult runInternal(AgentContext context, AgentRequest r...
    method buildPrompt (line 178) | @Override
    method runtimeInstructions (line 197) | private String runtimeInstructions(AgentContext context) {
    method hasTool (line 245) | private boolean hasTool(List<Object> tools, String name) {
    method buildToolGuide (line 259) | private String buildToolGuide(List<Object> tools) {
    method extractToolNames (line 281) | private List<String> extractToolNames(List<Object> tools) {
    method parseMessage (line 297) | private CodeActMessage parseMessage(String output) {
    method extractJson (line 318) | private String extractJson(String text) {
    method valueAsString (line 354) | private String valueAsString(Object value) {
    method buildToolOutput (line 358) | private String buildToolOutput(CodeExecutionResult result) {
    method resolveDirectOutput (line 375) | private String resolveDirectOutput(CodeExecutionResult result) {
    method resolveFallbackOutput (line 393) | private String resolveFallbackOutput(CodeExecutionResult result, Strin...
    method mergeText (line 409) | private String mergeText(String base, String extra) {
    class CodeActMessage (line 419) | private static class CodeActMessage {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/runtime/DeepResearchRuntime.java
  class DeepResearchRuntime (line 9) | public class DeepResearchRuntime extends BaseAgentRuntime {
    method DeepResearchRuntime (line 13) | public DeepResearchRuntime() {
    method DeepResearchRuntime (line 17) | public DeepResearchRuntime(Planner planner) {
    method runtimeName (line 21) | @Override
    method runtimeInstructions (line 26) | @Override
    method run (line 31) | @Override
    method runStream (line 37) | @Override
    method preparePlan (line 43) | private void preparePlan(AgentContext context, AgentRequest request) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/runtime/Planner.java
  type Planner (line 6) | public interface Planner {
    method plan (line 8) | List<String> plan(String goal);
    method simple (line 10) | static Planner simple() {
    class SimplePlanner (line 14) | class SimplePlanner implements Planner {
      method plan (line 15) | @Override

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/runtime/ReActRuntime.java
  class ReActRuntime (line 3) | public class ReActRuntime extends BaseAgentRuntime {
    method runtimeName (line 5) | @Override
    method runtimeInstructions (line 10) | @Override

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/subagent/HandoffContext.java
  class HandoffContext (line 3) | public final class HandoffContext {
    method HandoffContext (line 7) | private HandoffContext() {
    method currentDepth (line 10) | public static int currentDepth() {
    method runWithDepth (line 15) | public static <T> T runWithDepth(int depth, HandoffCallable<T> callabl...
    type HandoffCallable (line 29) | public interface HandoffCallable<T> {
      method call (line 30) | T call() throws Exception;

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/subagent/HandoffFailureAction.java
  type HandoffFailureAction (line 3) | public enum HandoffFailureAction {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/subagent/HandoffInputFilter.java
  type HandoffInputFilter (line 5) | public interface HandoffInputFilter {
    method filter (line 7) | AgentToolCall filter(AgentToolCall call) throws Exception;

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/subagent/HandoffPolicy.java
  class HandoffPolicy (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/subagent/StaticSubAgentRegistry.java
  class StaticSubAgentRegistry (line 20) | public class StaticSubAgentRegistry implements SubAgentRegistry {
    method StaticSubAgentRegistry (line 24) | public StaticSubAgentRegistry(List<SubAgentDefinition> definitions) {
    method getTools (line 40) | @Override
    method supports (line 52) | @Override
    method getDefinition (line 57) | @Override
    method execute (line 63) | @Override
    method resolveInput (line 82) | private String resolveInput(String arguments) {
    method trimToNull (line 105) | private String trimToNull(String value) {
    class RuntimeSubAgent (line 113) | private static class RuntimeSubAgent {
      method RuntimeSubAgent (line 122) | private RuntimeSubAgent(String name, String toolName, Agent agent, S...
      method invoke (line 130) | private AgentResult invoke(String input) throws Exception {
      method from (line 141) | private static RuntimeSubAgent from(SubAgentDefinition definition) {
      method toDefinition (line 167) | private SubAgentDefinition toDefinition() {
      method createTool (line 177) | private static Tool createTool(String toolName, String description) {
      method normalizeToolName (line 199) | private static String normalizeToolName(String raw) {
      method trimToNull (line 213) | private static String trimToNull(String value) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/subagent/SubAgentDefinition.java
  class SubAgentDefinition (line 7) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/subagent/SubAgentRegistry.java
  type SubAgentRegistry (line 7) | public interface SubAgentRegistry {
    method getTools (line 9) | List<Object> getTools();
    method supports (line 11) | boolean supports(String toolName);
    method getDefinition (line 13) | default SubAgentDefinition getDefinition(String toolName) {
    method execute (line 17) | String execute(AgentToolCall call) throws Exception;

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/subagent/SubAgentSessionMode.java
  type SubAgentSessionMode (line 3) | public enum SubAgentSessionMode {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/subagent/SubAgentToolExecutor.java
  class SubAgentToolExecutor (line 26) | public class SubAgentToolExecutor implements ToolExecutor {
    method newThread (line 30) | @Override
    method SubAgentToolExecutor (line 44) | public SubAgentToolExecutor(SubAgentRegistry subAgentRegistry, ToolExe...
    method SubAgentToolExecutor (line 48) | public SubAgentToolExecutor(SubAgentRegistry subAgentRegistry, ToolExe...
    method execute (line 56) | @Override
    method executeSubAgent (line 71) | private String executeSubAgent(AgentToolCall call, String toolName) th...
    method executeWithoutPolicy (line 127) | private String executeWithoutPolicy(AgentToolCall call, String toolNam...
    method applyInputFilter (line 179) | private AgentToolCall applyInputFilter(AgentToolCall call) throws Exce...
    method executeOnce (line 188) | private String executeOnce(AgentToolCall call, int depth, String toolN...
    method onDenied (line 211) | private String onDenied(AgentToolCall call,
    method onError (line 268) | private String onError(AgentToolCall call,
    method denyReason (line 329) | private String denyReason(String toolName, int nextDepth) {
    method toSafeSet (line 342) | private Set<String> toSafeSet(Set<String> source) {
    method emitHandoffEvent (line 349) | private void emitHandoffEvent(AgentEventType type, Map<String, Object>...
    method buildHandoffPayload (line 357) | private Map<String, Object> buildHandoffPayload(String handoffId,
    method resolveSubAgentName (line 388) | private String resolveSubAgentName(SubAgentDefinition definition, Stri...
    method resolveHandoffId (line 393) | private String resolveHandoffId(AgentToolCall call) {
    method extractResultOutput (line 398) | private String extractResultOutput(String raw) {
    method safeMessage (line 412) | private String safeMessage(Throwable throwable) {
    method firstNonBlank (line 427) | private String firstNonBlank(String... values) {
    method trimToNull (line 440) | private String trimToNull(String value) {
    method isBlank (line 448) | private boolean isBlank(String value) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeam.java
  class AgentTeam (line 26) | public class AgentTeam implements AgentTeamControl {
    method AgentTeam (line 54) | AgentTeam(AgentTeamBuilder builder) {
    method builder (line 115) | public static AgentTeamBuilder builder() {
    method getTeamId (line 119) | public String getTeamId() {
    method snapshotState (line 123) | public AgentTeamState snapshotState() {
    method loadPersistedState (line 139) | public AgentTeamState loadPersistedState() {
    method restoreState (line 148) | public void restoreState(AgentTeamState state) {
    method clearPersistedState (line 169) | public boolean clearPersistedState() {
    method registerMember (line 188) | @Override
    method unregisterMember (line 204) | @Override
    method listMembers (line 230) | @Override
    method listMessages (line 235) | @Override
    method listMessagesFor (line 243) | @Override
    method publishMessage (line 255) | @Override
    method sendMessage (line 260) | @Override
    method broadcastMessage (line 269) | @Override
    method listTaskStates (line 276) | @Override
    method claimTask (line 290) | @Override
    method releaseTask (line 306) | @Override
    method reassignTask (line 322) | @Override
    method heartbeatTask (line 340) | @Override
    method run (line 356) | public AgentTeamResult run(String objective) throws Exception {
    method run (line 360) | public AgentTeamResult run(AgentRequest request) throws Exception {
    method ensurePlanApproved (line 426) | private void ensurePlanApproved(String objective, AgentTeamPlan plan, ...
    method dispatchTasks (line 439) | private DispatchOutcome dispatchTasks(String objective, AgentTeamTaskB...
    method executeRound (line 510) | private List<AgentTeamMemberResult> executeRound(String objective,
    method waitForFuture (line 545) | private AgentTeamMemberResult waitForFuture(Future<AgentTeamMemberResu...
    method executePreparedTask (line 560) | private AgentTeamMemberResult executePreparedTask(String objective,
    method runMemberTask (line 610) | private AgentResult runMemberTask(PreparedDispatch dispatch, String in...
    method buildDispatchInput (line 635) | private String buildDispatchInput(String objective, RuntimeMember memb...
    method publishMessage (line 675) | private void publishMessage(String from,
    method publishMessageInternal (line 695) | private void publishMessageInternal(AgentTeamMessage message) {
    method resolveMember (line 719) | private RuntimeMember resolveMember(String requestedId) {
    method snapshotMembers (line 739) | private List<AgentTeamMember> snapshotMembers() {
    method currentBoard (line 749) | private AgentTeamTaskBoard currentBoard() {
    method snapshotMemberViews (line 755) | private List<AgentTeamMemberSnapshot> snapshotMemberViews() {
    method rememberTaskStates (line 765) | private void rememberTaskStates(List<AgentTeamTaskState> taskStates) {
    method currentObjective (line 776) | private String currentObjective() {
    method resolveMessageBus (line 782) | private AgentTeamMessageBus resolveMessageBus(AgentTeamBuilder builder) {
    method resolveStateStore (line 796) | private AgentTeamStateStore resolveStateStore(AgentTeamBuilder builder) {
    method persistState (line 806) | private void persistState() {
    method isSameTeam (line 813) | private boolean isSameTeam(AgentTeamState state) {
    method copyTaskStates (line 817) | private List<AgentTeamTaskState> copyTaskStates(List<AgentTeamTaskStat...
    method copyMessages (line 828) | private List<AgentTeamMessage> copyMessages(List<AgentTeamMessage> mes...
    method resolveMemberView (line 839) | private AgentTeamMember resolveMemberView(String memberId) {
    method fireTaskStateChanged (line 849) | private void fireTaskStateChanged(AgentTeamTaskState state, AgentTeamM...
    method validateKnownMemberId (line 859) | private void validateKnownMemberId(String memberId, boolean allowReser...
    method isReservedMember (line 873) | private boolean isReservedMember(String memberId) {
    method fireBeforePlan (line 878) | private void fireBeforePlan(String objective, List<AgentTeamMember> me...
    method fireAfterPlan (line 888) | private void fireAfterPlan(String objective, AgentTeamPlan plan) {
    method fireBeforeTask (line 898) | private void fireBeforeTask(String objective, AgentTeamTask task, Agen...
    method fireAfterTask (line 908) | private void fireAfterTask(String objective, AgentTeamMemberResult res...
    method fireAfterSynthesis (line 918) | private void fireAfterSynthesis(String objective, AgentResult synthesi...
    method normalize (line 930) | private String normalize(String raw) {
    method safe (line 945) | private String safe(String value) {
    method firstNonBlank (line 949) | private String firstNonBlank(String... values) {
    method safeShort (line 961) | private String safeShort(String value) {
    method toText (line 972) | private String toText(Object value) {
    class RuntimeMember (line 982) | private static class RuntimeMember {
      method RuntimeMember (line 988) | private RuntimeMember(String id, String name, String description, Ag...
      method from (line 995) | private static RuntimeMember from(AgentTeamMember member) {
      method toPublicMember (line 1010) | private AgentTeamMember toPublicMember() {
    class PreparedDispatch (line 1020) | private static class PreparedDispatch {
      method PreparedDispatch (line 1025) | private PreparedDispatch(String taskId, AgentTeamTask task, RuntimeM...
    class DispatchOutcome (line 1032) | private static class DispatchOutcome {
      method DispatchOutcome (line 1036) | private DispatchOutcome(List<AgentTeamMemberResult> results, int rou...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamAgentRuntime.java
  class AgentTeamAgentRuntime (line 14) | public class AgentTeamAgentRuntime implements AgentRuntime {
    method AgentTeamAgentRuntime (line 18) | public AgentTeamAgentRuntime(AgentTeamBuilder template) {
    method run (line 25) | @Override
    method runStream (line 32) | @Override
    method prepareTeam (line 56) | private AgentTeam prepareTeam(AgentListener listener) {
    method copyBuilder (line 62) | private AgentTeamBuilder copyBuilder(AgentTeamBuilder source) {
    method toAgentResult (line 84) | private AgentResult toAgentResult(AgentTeamResult result) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamBuilder.java
  class AgentTeamBuilder (line 13) | public class AgentTeamBuilder {
    method builder (line 29) | public static AgentTeamBuilder builder() {
    method getLeadAgent (line 33) | public Agent getLeadAgent() {
    method getPlannerAgent (line 37) | public Agent getPlannerAgent() {
    method getSynthesizerAgent (line 41) | public Agent getSynthesizerAgent() {
    method getPlanner (line 45) | public AgentTeamPlanner getPlanner() {
    method getSynthesizer (line 49) | public AgentTeamSynthesizer getSynthesizer() {
    method getMembers (line 53) | public List<AgentTeamMember> getMembers() {
    method getOptions (line 57) | public AgentTeamOptions getOptions() {
    method getMessageBus (line 61) | public AgentTeamMessageBus getMessageBus() {
    method getStateStore (line 65) | public AgentTeamStateStore getStateStore() {
    method getTeamId (line 69) | public String getTeamId() {
    method getStorageDirectory (line 73) | public Path getStorageDirectory() {
    method getPlanApproval (line 77) | public AgentTeamPlanApproval getPlanApproval() {
    method getHooks (line 81) | public List<AgentTeamHook> getHooks() {
    method leadAgent (line 85) | public AgentTeamBuilder leadAgent(Agent leadAgent) {
    method plannerAgent (line 90) | public AgentTeamBuilder plannerAgent(Agent plannerAgent) {
    method synthesizerAgent (line 95) | public AgentTeamBuilder synthesizerAgent(Agent synthesizerAgent) {
    method planner (line 100) | public AgentTeamBuilder planner(AgentTeamPlanner planner) {
    method synthesizer (line 105) | public AgentTeamBuilder synthesizer(AgentTeamSynthesizer synthesizer) {
    method member (line 110) | public AgentTeamBuilder member(AgentTeamMember member) {
    method members (line 117) | public AgentTeamBuilder members(List<AgentTeamMember> members) {
    method options (line 124) | public AgentTeamBuilder options(AgentTeamOptions options) {
    method messageBus (line 129) | public AgentTeamBuilder messageBus(AgentTeamMessageBus messageBus) {
    method stateStore (line 134) | public AgentTeamBuilder stateStore(AgentTeamStateStore stateStore) {
    method teamId (line 139) | public AgentTeamBuilder teamId(String teamId) {
    method storageDirectory (line 144) | public AgentTeamBuilder storageDirectory(Path storageDirectory) {
    method planApproval (line 149) | public AgentTeamBuilder planApproval(AgentTeamPlanApproval planApprova...
    method hook (line 154) | public AgentTeamBuilder hook(AgentTeamHook hook) {
    method hooks (line 161) | public AgentTeamBuilder hooks(List<AgentTeamHook> hooks) {
    method build (line 168) | public AgentTeam build() {
    method buildAgent (line 172) | public Agent buildAgent() {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamControl.java
  type AgentTeamControl (line 5) | public interface AgentTeamControl {
    method registerMember (line 7) | void registerMember(AgentTeamMember member);
    method unregisterMember (line 9) | boolean unregisterMember(String memberId);
    method listMembers (line 11) | List<AgentTeamMember> listMembers();
    method listMessages (line 13) | List<AgentTeamMessage> listMessages();
    method listMessagesFor (line 15) | List<AgentTeamMessage> listMessagesFor(String memberId, int limit);
    method publishMessage (line 17) | void publishMessage(AgentTeamMessage message);
    method sendMessage (line 19) | void sendMessage(String fromMemberId, String toMemberId, String type, ...
    method broadcastMessage (line 21) | void broadcastMessage(String fromMemberId, String type, String taskId,...
    method listTaskStates (line 23) | List<AgentTeamTaskState> listTaskStates();
    method claimTask (line 25) | boolean claimTask(String taskId, String memberId);
    method releaseTask (line 27) | boolean releaseTask(String taskId, String memberId, String reason);
    method reassignTask (line 29) | boolean reassignTask(String taskId, String fromMemberId, String toMemb...
    method heartbeatTask (line 31) | boolean heartbeatTask(String taskId, String memberId);

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamEventHook.java
  class AgentTeamEventHook (line 12) | public class AgentTeamEventHook implements AgentTeamHook {
    method AgentTeamEventHook (line 16) | public AgentTeamEventHook() {
    method AgentTeamEventHook (line 20) | public AgentTeamEventHook(AgentListener listener) {
    method afterPlan (line 24) | @Override
    method beforeTask (line 46) | @Override
    method afterTask (line 63) | @Override
    method onTaskStateChanged (line 86) | @Override
    method onMessage (line 108) | @Override
    method buildTaskPayload (line 126) | private Map<String, Object> buildTaskPayload(AgentTeamTask task,
    method buildTaskSummary (line 165) | private String buildTaskSummary(AgentTeamTask task, String status) {
    method normalizeStatus (line 169) | private String normalizeStatus(AgentTeamTaskStatus status) {
    method resolvePercent (line 173) | private int resolvePercent(String status, Integer statePercent) {
    method emit (line 193) | private void emit(AgentEventType type, String message, Map<String, Obj...
    method firstNonBlank (line 204) | private String firstNonBlank(String... values) {
    method isBlank (line 216) | private boolean isBlank(String value) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamHook.java
  type AgentTeamHook (line 7) | public interface AgentTeamHook {
    method beforePlan (line 9) | default void beforePlan(String objective, List<AgentTeamMember> member...
    method afterPlan (line 12) | default void afterPlan(String objective, AgentTeamPlan plan) {
    method beforeTask (line 15) | default void beforeTask(String objective, AgentTeamTask task, AgentTea...
    method afterTask (line 18) | default void afterTask(String objective, AgentTeamMemberResult result) {
    method onTaskStateChanged (line 21) | default void onTaskStateChanged(String objective,
    method afterSynthesis (line 27) | default void afterSynthesis(String objective, AgentResult result) {
    method onMessage (line 30) | default void onMessage(AgentTeamMessage message) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamMember.java
  class AgentTeamMember (line 7) | @Data
    method resolveId (line 19) | public String resolveId() {
    method normalize (line 31) | private String normalize(String raw) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamMemberResult.java
  class AgentTeamMemberResult (line 7) | @Data
    method isSuccess (line 29) | public boolean isSuccess() {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamMemberSnapshot.java
  class AgentTeamMemberSnapshot (line 6) | @Data
    method from (line 16) | public static AgentTeamMemberSnapshot from(AgentTeamMember member) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamMessage.java
  class AgentTeamMessage (line 6) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamMessageBus.java
  type AgentTeamMessageBus (line 5) | public interface AgentTeamMessageBus {
    method publish (line 7) | void publish(AgentTeamMessage message);
    method snapshot (line 9) | List<AgentTeamMessage> snapshot();
    method historyFor (line 11) | List<AgentTeamMessage> historyFor(String memberId, int limit);
    method clear (line 13) | void clear();
    method restore (line 15) | void restore(List<AgentTeamMessage> messages);

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamOptions.java
  class AgentTeamOptions (line 6) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamPlan.java
  class AgentTeamPlan (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamPlanApproval.java
  type AgentTeamPlanApproval (line 5) | public interface AgentTeamPlanApproval {
    method approve (line 7) | boolean approve(String objective,

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamPlanParser.java
  class AgentTeamPlanParser (line 11) | final class AgentTeamPlanParser {
    method AgentTeamPlanParser (line 13) | private AgentTeamPlanParser() {
    method parseTasks (line 16) | static List<AgentTeamTask> parseTasks(String rawText) {
    method parseFromJson (line 33) | private static List<AgentTeamTask> parseFromJson(String text) {
    method firstArray (line 66) | private static JSONArray firstArray(JSONObject obj, String... keys) {
    method parseArray (line 79) | private static List<AgentTeamTask> parseArray(JSONArray array) {
    method parseTask (line 96) | private static AgentTeamTask parseTask(JSONObject obj) {
    method parseDependencies (line 117) | private static List<String> parseDependencies(Object raw) {
    method firstValue (line 147) | private static Object firstValue(JSONObject obj, String... keys) {
    method firstString (line 159) | private static String firstString(JSONObject obj, String... keys) {
    method extractJson (line 170) | private static String extractJson(String text) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamPlanner.java
  type AgentTeamPlanner (line 5) | public interface AgentTeamPlanner {
    method plan (line 7) | AgentTeamPlan plan(String objective, List<AgentTeamMember> members, Ag...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamResult.java
  class AgentTeamResult (line 9) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamState.java
  class AgentTeamState (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamStateStore.java
  type AgentTeamStateStore (line 5) | public interface AgentTeamStateStore {
    method save (line 7) | void save(AgentTeamState state);
    method load (line 9) | AgentTeamState load(String teamId);
    method list (line 11) | List<AgentTeamState> list();
    method delete (line 13) | boolean delete(String teamId);

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamSynthesizer.java
  type AgentTeamSynthesizer (line 7) | public interface AgentTeamSynthesizer {
    method synthesize (line 9) | AgentResult synthesize(String objective,

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamTask.java
  class AgentTeamTask (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamTaskBoard.java
  class AgentTeamTaskBoard (line 11) | public class AgentTeamTaskBoard {
    method AgentTeamTaskBoard (line 19) | public AgentTeamTaskBoard(List<AgentTeamTask> tasks) {
    method initialize (line 23) | private void initialize(List<AgentTeamTask> tasks) {
    method normalizedTasks (line 60) | public synchronized List<AgentTeamTask> normalizedTasks() {
    method nextReadyTasks (line 71) | public synchronized List<AgentTeamTaskState> nextReadyTasks(int maxCou...
    method getTaskState (line 89) | public synchronized AgentTeamTaskState getTaskState(String taskId) {
    method claimTask (line 97) | public synchronized boolean claimTask(String taskId, String memberId) {
    method releaseTask (line 126) | public synchronized boolean releaseTask(String taskId, String memberId...
    method reassignTask (line 155) | public synchronized boolean reassignTask(String taskId, String fromMem...
    method heartbeatTask (line 182) | public synchronized boolean heartbeatTask(String taskId, String member...
    method recoverTimedOutClaims (line 206) | public synchronized int recoverTimedOutClaims(long timeoutMillis, Stri...
    method markInProgress (line 242) | public synchronized void markInProgress(String taskId, String claimedB...
    method markCompleted (line 246) | public synchronized void markCompleted(String taskId, String output, l...
    method markFailed (line 271) | public synchronized void markFailed(String taskId, String error, long ...
    method markStalledAsBlocked (line 295) | public synchronized void markStalledAsBlocked(String reason) {
    method hasWorkRemaining (line 312) | public synchronized boolean hasWorkRemaining() {
    method hasFailed (line 323) | public synchronized boolean hasFailed() {
    method snapshot (line 332) | public synchronized List<AgentTeamTaskState> snapshot() {
    method size (line 343) | public synchronized int size() {
    method refreshStatuses (line 347) | private void refreshStatuses() {
    method resolveTaskKey (line 432) | private String resolveTaskKey(String taskId) {
    method normalizeDependencies (line 450) | private List<String> normalizeDependencies(List<String> dependencies) {
    method normalizeId (line 464) | private String normalizeId(String raw) {
    method normalizeMemberId (line 479) | private String normalizeMemberId(String memberId) {
    method isSameMember (line 487) | private boolean isSameMember(String currentClaimedBy, String expectedM...
    method copy (line 496) | private AgentTeamTaskState copy(AgentTeamTaskState state) {
    method percentOf (line 503) | private int percentOf(AgentTeamTaskState state) {
    method selectUpdatedAt (line 508) | private long selectUpdatedAt(AgentTeamTaskState state) {
    method trimToNull (line 515) | private String trimToNull(String value) {
    method firstNonBlank (line 523) | private String firstNonBlank(String... values) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamTaskState.java
  class AgentTeamTaskState (line 6) | @Data
    method isTerminal (line 40) | public boolean isTerminal() {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/AgentTeamTaskStatus.java
  type AgentTeamTaskStatus (line 3) | public enum AgentTeamTaskStatus {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/FileAgentTeamMessageBus.java
  class FileAgentTeamMessageBus (line 14) | public class FileAgentTeamMessageBus implements AgentTeamMessageBus {
    method FileAgentTeamMessageBus (line 19) | public FileAgentTeamMessageBus(Path file) {
    method publish (line 27) | @Override
    method snapshot (line 36) | @Override
    method historyFor (line 44) | @Override
    method clear (line 67) | @Override
    method restore (line 73) | @Override
    method loadExistingMessages (line 82) | private void loadExistingMessages() {
    method append (line 102) | private void append(AgentTeamMessage message) {
    method rewriteAll (line 115) | private void rewriteAll() {
    method ensureParent (line 133) | private void ensureParent() throws IOException {
    method copyMessages (line 140) | private List<AgentTeamMessage> copyMessages(List<AgentTeamMessage> sou...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/FileAgentTeamStateStore.java
  class FileAgentTeamStateStore (line 14) | public class FileAgentTeamStateStore implements AgentTeamStateStore {
    method FileAgentTeamStateStore (line 18) | public FileAgentTeamStateStore(Path directory) {
    method save (line 25) | @Override
    method load (line 42) | @Override
    method list (line 62) | @Override
    method delete (line 98) | @Override
    method ensureDirectory (line 110) | private void ensureDirectory() throws IOException {
    method fileOf (line 114) | private Path fileOf(String teamId) {
    method isBlank (line 118) | private boolean isBlank(String value) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/InMemoryAgentTeamMessageBus.java
  class InMemoryAgentTeamMessageBus (line 7) | public class InMemoryAgentTeamMessageBus implements AgentTeamMessageBus {
    method publish (line 11) | @Override
    method snapshot (line 19) | @Override
    method historyFor (line 27) | @Override
    method clear (line 50) | @Override
    method restore (line 55) | @Override

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/InMemoryAgentTeamStateStore.java
  class InMemoryAgentTeamStateStore (line 10) | public class InMemoryAgentTeamStateStore implements AgentTeamStateStore {
    method save (line 14) | @Override
    method load (line 22) | @Override
    method list (line 28) | @Override
    method delete (line 48) | @Override
    method copy (line 53) | private AgentTeamState copy(AgentTeamState state) {
    method copyMembers (line 64) | private List<AgentTeamMemberSnapshot> copyMembers(List<AgentTeamMember...
    method copyTaskStates (line 75) | private List<AgentTeamTaskState> copyTaskStates(List<AgentTeamTaskStat...
    method copyMessages (line 86) | private List<AgentTeamMessage> copyMessages(List<AgentTeamMessage> mes...
    method isBlank (line 97) | private boolean isBlank(String value) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/LlmAgentTeamPlanner.java
  class LlmAgentTeamPlanner (line 11) | public class LlmAgentTeamPlanner implements AgentTeamPlanner {
    method LlmAgentTeamPlanner (line 15) | public LlmAgentTeamPlanner(Agent plannerAgent) {
    method plan (line 22) | @Override
    method buildPlannerPrompt (line 43) | private String buildPlannerPrompt(String objective, List<AgentTeamMemb...
    method fallbackTasks (line 67) | private List<AgentTeamTask> fallbackTasks(String objective, List<Agent...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/LlmAgentTeamSynthesizer.java
  class LlmAgentTeamSynthesizer (line 11) | public class LlmAgentTeamSynthesizer implements AgentTeamSynthesizer {
    method LlmAgentTeamSynthesizer (line 15) | public LlmAgentTeamSynthesizer(Agent synthesizerAgent) {
    method synthesize (line 22) | @Override
    method buildSynthesisPrompt (line 31) | private String buildSynthesisPrompt(String objective,

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/tool/AgentTeamToolExecutor.java
  class AgentTeamToolExecutor (line 13) | public class AgentTeamToolExecutor implements ToolExecutor {
    method AgentTeamToolExecutor (line 20) | public AgentTeamToolExecutor(AgentTeamControl control,
    method execute (line 36) | @Override
    method handleSendMessage (line 74) | private String handleSendMessage(JSONObject args) {
    method handleBroadcast (line 97) | private String handleBroadcast(JSONObject args) {
    method handleListTasks (line 115) | private String handleListTasks() {
    method handleClaimTask (line 122) | private String handleClaimTask(JSONObject args) {
    method handleReleaseTask (line 131) | private String handleReleaseTask(JSONObject args) {
    method handleReassignTask (line 141) | private String handleReassignTask(JSONObject args) {
    method handleHeartbeatTask (line 155) | private String handleHeartbeatTask(JSONObject args) {
    method parseArguments (line 164) | private JSONObject parseArguments(String raw) {
    method resolveTaskId (line 176) | private String resolveTaskId(JSONObject args, boolean required) {
    method findTaskState (line 187) | private AgentTeamTaskState findTaskState(String taskId) {
    method firstString (line 206) | private String firstString(JSONObject args, String... keys) {
    method baseResult (line 222) | private JSONObject baseResult(String action, boolean ok) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/team/tool/AgentTeamToolRegistry.java
  class AgentTeamToolRegistry (line 15) | public class AgentTeamToolRegistry implements AgentToolRegistry {
    method AgentTeamToolRegistry (line 37) | public AgentTeamToolRegistry() {
    method getTools (line 41) | @Override
    method supports (line 46) | public static boolean supports(String toolName) {
    method buildTools (line 50) | private List<Object> buildTools() {
    method createSendMessageTool (line 62) | private Tool createSendMessageTool() {
    method createBroadcastTool (line 74) | private Tool createBroadcastTool() {
    method createListTasksTool (line 85) | private Tool createListTasksTool() {
    method createClaimTaskTool (line 93) | private Tool createClaimTaskTool() {
    method createReleaseTaskTool (line 102) | private Tool createReleaseTaskTool() {
    method createReassignTaskTool (line 112) | private Tool createReassignTaskTool() {
    method createHeartbeatTaskTool (line 122) | private Tool createHeartbeatTaskTool() {
    method createTool (line 131) | private Tool createTool(String name,
    method stringProperty (line 151) | private Tool.Function.Property stringProperty(String description) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/tool/AgentToolCall.java
  class AgentToolCall (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/tool/AgentToolCallSanitizer.java
  class AgentToolCallSanitizer (line 9) | public final class AgentToolCallSanitizer {
    method AgentToolCallSanitizer (line 11) | private AgentToolCallSanitizer() {
    method retainExecutableCalls (line 14) | public static List<AgentToolCall> retainExecutableCalls(List<AgentTool...
    method validationError (line 27) | public static String validationError(AgentToolCall call) {
    method isExecutable (line 54) | public static boolean isExecutable(AgentToolCall call) {
    method isExecutableBashCall (line 58) | private static boolean isExecutableBashCall(JSONObject arguments) {
    method bashValidationError (line 75) | private static String bashValidationError(JSONObject arguments) {
    method parseObject (line 92) | private static JSONObject parseObject(String value) {
    method firstNonBlank (line 103) | private static String firstNonBlank(String... values) {
    method isBlank (line 115) | private static boolean isBlank(String value) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/tool/AgentToolRegistry.java
  type AgentToolRegistry (line 5) | public interface AgentToolRegistry {
    method getTools (line 7) | List<Object> getTools();

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/tool/AgentToolResult.java
  class AgentToolResult (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/tool/CompositeToolRegistry.java
  class CompositeToolRegistry (line 7) | public class CompositeToolRegistry implements AgentToolRegistry {
    method CompositeToolRegistry (line 11) | public CompositeToolRegistry(List<AgentToolRegistry> registries) {
    method CompositeToolRegistry (line 19) | public CompositeToolRegistry(AgentToolRegistry first, AgentToolRegistr...
    method getTools (line 30) | @Override

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/tool/StaticToolRegistry.java
  class StaticToolRegistry (line 7) | public class StaticToolRegistry implements AgentToolRegistry {
    method StaticToolRegistry (line 11) | public StaticToolRegistry(List<Object> tools) {
    method getTools (line 19) | @Override
    method empty (line 24) | public static StaticToolRegistry empty() {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/tool/ToolExecutor.java
  type ToolExecutor (line 3) | public interface ToolExecutor {
    method execute (line 5) | String execute(AgentToolCall call) throws Exception;

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/tool/ToolUtilExecutor.java
  class ToolUtilExecutor (line 9) | public class ToolUtilExecutor implements ToolExecutor {
    method ToolUtilExecutor (line 13) | public ToolUtilExecutor() {
    method ToolUtilExecutor (line 17) | public ToolUtilExecutor(Set<String> allowedToolNames) {
    method execute (line 25) | @Override

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/tool/ToolUtilRegistry.java
  class ToolUtilRegistry (line 9) | public class ToolUtilRegistry implements AgentToolRegistry {
    method ToolUtilRegistry (line 14) | public ToolUtilRegistry(List<String> functionList, List<String> mcpSer...
    method getTools (line 19) | @Override

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/AbstractOpenTelemetryTraceExporter.java
  class AbstractOpenTelemetryTraceExporter (line 14) | abstract class AbstractOpenTelemetryTraceExporter implements TraceExport...
    method AbstractOpenTelemetryTraceExporter (line 22) | protected AbstractOpenTelemetryTraceExporter(OpenTelemetry openTelemet...
    method AbstractOpenTelemetryTraceExporter (line 26) | protected AbstractOpenTelemetryTraceExporter(Tracer tracer) {
    method export (line 33) | @Override
    method customizeSpan (line 46) | protected void customizeSpan(Span span, TraceSpan traceSpan) {
    method flushReadySpans (line 49) | private void flushReadySpans(String traceId) {
    method emitSpan (line 72) | private void emitSpan(TraceSpan traceSpan, Span parentSpan) {
    method cleanupIfTraceComplete (line 89) | private void cleanupIfTraceComplete(String traceId) {
    method hasPendingTrace (line 104) | private boolean hasPendingTrace(String traceId) {
    method sameTrace (line 113) | private boolean sameTrace(String left, String right) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/AgentFlowTraceBridge.java
  class AgentFlowTraceBridge (line 21) | public class AgentFlowTraceBridge implements AgentFlowTraceListener {
    method AgentFlowTraceBridge (line 27) | public AgentFlowTraceBridge(TraceExporter exporter) {
    method AgentFlowTraceBridge (line 31) | public AgentFlowTraceBridge(TraceExporter exporter, TraceConfig config) {
    method onStart (line 39) | @Override
    method onEvent (line 56) | @Override
    method onComplete (line 73) | @Override
    method onError (line 89) | @Override
    method span (line 98) | private TraceSpan span(AgentFlowTraceContext context) {
    method removeSpan (line 105) | private TraceSpan removeSpan(AgentFlowTraceContext context) {
    method spanName (line 112) | private String spanName(AgentFlowTraceContext context) {
    method startAttributes (line 117) | private Map<String, Object> startAttributes(AgentFlowTraceContext cont...
    method applyRequest (line 136) | private void applyRequest(Map<String, Object> attributes, Object reque...
    method applyChatEvent (line 162) | private void applyChatEvent(TraceSpan span, AgentFlowChatEvent event) {
    method applyWorkflowEvent (line 185) | private void applyWorkflowEvent(TraceSpan span, AgentFlowWorkflowEvent...
    method applyChatResponse (line 208) | private void applyChatResponse(TraceSpan span, AgentFlowChatResponse r...
    method applyWorkflowResponse (line 222) | private void applyWorkflowResponse(TraceSpan span, AgentFlowWorkflowRe...
    method applyUsage (line 237) | private void applyUsage(TraceSpan span, AgentFlowUsage usage) {
    method finishSpan (line 257) | private void finishSpan(TraceSpan span, TraceSpanStatus status, String...
    method addSpanEvent (line 273) | private void addSpanEvent(TraceSpan span, String name, Map<String, Obj...
    method putAttribute (line 289) | private void putAttribute(TraceSpan span, String key, Object value) {
    method putIfPresent (line 301) | private void putIfPresent(Map<String, Object> target, String key, Obje...
    method singletonAttribute (line 307) | private Map<String, Object> singletonAttribute(String key, Object valu...
    method safeValue (line 315) | private Object safeValue(Object value) {
    method safeText (line 330) | private String safeText(String value) {
    method isBlank (line 335) | private boolean isBlank(String value) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/AgentTraceListener.java
  class AgentTraceListener (line 22) | public class AgentTraceListener implements AgentListener {
    method AgentTraceListener (line 35) | public AgentTraceListener(TraceExporter exporter) {
    method AgentTraceListener (line 39) | public AgentTraceListener(TraceExporter exporter, TraceConfig config) {
    method onEvent (line 44) | @Override
    method onStepStart (line 107) | private void onStepStart(AgentEvent event) {
    method onStepEnd (line 120) | private void onStepEnd(AgentEvent event) {
    method onModelRequest (line 133) | private void onModelRequest(AgentEvent event) {
    method onModelResponse (line 167) | private void onModelResponse(AgentEvent event) {
    method onModelRetry (line 192) | private void onModelRetry(AgentEvent event) {
    method onModelReasoning (line 197) | private void onModelReasoning(AgentEvent event) {
    method onToolCall (line 206) | private void onToolCall(AgentEvent event) {
    method onToolResult (line 243) | private void onToolResult(AgentEvent event) {
    method onFinalOutput (line 278) | private void onFinalOutput(AgentEvent event) {
    method onError (line 285) | private void onError(AgentEvent event) {
    method onHandoffStart (line 290) | private void onHandoffStart(AgentEvent event) {
    method onHandoffEnd (line 301) | private void onHandoffEnd(AgentEvent event) {
    method onTeamTaskCreated (line 318) | private void onTeamTaskCreated(AgentEvent event) {
    method onTeamTaskUpdated (line 329) | private void onTeamTaskUpdated(AgentEvent event) {
    method onTeamMessage (line 352) | private void onTeamMessage(AgentEvent event) {
    method onMemoryCompress (line 359) | private void onMemoryCompress(AgentEvent event) {
    method startSpan (line 365) | private TraceSpan startSpan(String name, TraceSpanType type, String pa...
    method resolveModelSpan (line 381) | private TraceSpan resolveModelSpan(Integer step) {
    method resolveHandoffParent (line 388) | private TraceSpan resolveHandoffParent(AgentEvent event, Map<String, O...
    method enrichModelSpan (line 409) | private void enrichModelSpan(TraceSpan span, Object payload) {
    method accumulateModelMetrics (line 443) | private void accumulateModelMetrics(Integer step, TraceSpan modelSpan) {
    method mergeMetrics (line 453) | private void mergeMetrics(TraceSpan span, TraceMetrics metrics) {
    method mergeUsageMetrics (line 476) | private void mergeUsageMetrics(TraceSpan span, TraceMetrics source) {
    method metricsFromUsage (line 492) | private TraceMetrics metricsFromUsage(Usage usage, TracePricing pricin...
    method resolveModelPricing (line 526) | private TracePricing resolveModelPricing(TraceSpan span, String respon...
    method mapToUsage (line 541) | private Usage mapToUsage(Object value) {
    method firstChoiceFinishReason (line 556) | private String firstChoiceFinishReason(List<Choice> choices) {
    method putAttribute (line 563) | private void putAttribute(TraceSpan span, String key, Object value) {
    method mergeAttributes (line 578) | private void mergeAttributes(TraceSpan span, Map<String, Object> attri...
    method addSpanEvent (line 590) | private void addSpanEvent(TraceSpan span, String name, Map<String, Obj...
    method safeValue (line 606) | private Object safeValue(Object value) {
    method attributesFromEvent (line 626) | private Map<String, Object> attributesFromEvent(AgentEvent event) {
    method payloadMap (line 637) | @SuppressWarnings("unchecked")
    method safeAttributes (line 645) | private Map<String, Object> safeAttributes(Map<String, Object> source) {
    method singletonAttribute (line 656) | private Map<String, Object> singletonAttribute(String key, Object valu...
    method stringValue (line 664) | private String stringValue(Map<String, Object> payload, String key) {
    method resolveStatus (line 672) | private TraceSpanStatus resolveStatus(Map<String, Object> payload, Str...
    method isTerminalStatus (line 690) | private boolean isTerminalStatus(String status) {
    method firstNonBlank (line 702) | private String firstNonBlank(String... values) {
    method firstNonNull (line 714) | private Object firstNonNull(Object... values) {
    method sum (line 726) | private Long sum(Long left, Long right) {
    method sum (line 736) | private Double sum(Double left, Double right) {
    method longValue (line 746) | private long longValue(Object value) {
    method finishSpan (line 760) | private void finishSpan(TraceSpan span, TraceSpanStatus status, String...
    method keyForStep (line 781) | private String keyForStep(Integer step, String toolName) {
    method reset (line 788) | private void reset() {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/CompositeTraceExporter.java
  class CompositeTraceExporter (line 7) | public class CompositeTraceExporter implements TraceExporter {
    method CompositeTraceExporter (line 11) | public CompositeTraceExporter(TraceExporter... exporters) {
    method CompositeTraceExporter (line 15) | public CompositeTraceExporter(List<TraceExporter> exporters) {
    method export (line 27) | @Override

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/ConsoleTraceExporter.java
  class ConsoleTraceExporter (line 5) | public class ConsoleTraceExporter implements TraceExporter {
    method export (line 7) | @Override

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/InMemoryTraceExporter.java
  class InMemoryTraceExporter (line 7) | public class InMemoryTraceExporter implements TraceExporter {
    method export (line 11) | @Override
    method getSpans (line 18) | public synchronized List<TraceSpan> getSpans() {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/JsonlTraceExporter.java
  class JsonlTraceExporter (line 13) | public class JsonlTraceExporter implements TraceExporter, AutoCloseable {
    method JsonlTraceExporter (line 18) | public JsonlTraceExporter(String path) {
    method JsonlTraceExporter (line 22) | public JsonlTraceExporter(File file) {
    method JsonlTraceExporter (line 26) | public JsonlTraceExporter(Writer writer) {
    method JsonlTraceExporter (line 30) | private JsonlTraceExporter(Writer writer, boolean ownsWriter) {
    method export (line 38) | @Override
    method close (line 52) | @Override
    method createWriter (line 61) | private static Writer createWriter(File file) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/LangfuseTraceExporter.java
  class LangfuseTraceExporter (line 11) | public class LangfuseTraceExporter extends AbstractOpenTelemetryTraceExp...
    method LangfuseTraceExporter (line 16) | public LangfuseTraceExporter(OpenTelemetry openTelemetry) {
    method LangfuseTraceExporter (line 20) | public LangfuseTraceExporter(OpenTelemetry openTelemetry, String envir...
    method LangfuseTraceExporter (line 26) | public LangfuseTraceExporter(Tracer tracer) {
    method LangfuseTraceExporter (line 30) | public LangfuseTraceExporter(Tracer tracer, String environment, String...
    method customizeSpan (line 36) | @Override
    class LangfuseSpanAttributes (line 44) | static final class LangfuseSpanAttributes {
      method LangfuseSpanAttributes (line 46) | private LangfuseSpanAttributes() {
      method project (line 49) | static Map<String, Object> project(TraceSpan traceSpan, String envir...
      method applyModelAttributes (line 77) | private static void applyModelAttributes(Map<String, Object> project...
      method applyGenericObservation (line 139) | private static void applyGenericObservation(Map<String, Object> proj...
      method metadataAttributes (line 163) | private static Map<String, Object> metadataAttributes(Map<String, Ob...
      method isExcluded (line 177) | private static boolean isExcluded(String key, String... excludedKeys) {
      method pick (line 189) | private static Map<String, Object> pick(Map<String, Object> attribut...
      method firstNonNull (line 203) | private static Object firstNonNull(Object... values) {
      method stringValue (line 215) | private static String stringValue(Map<String, Object> attributes, St...
      method putIfPresent (line 223) | private static void putIfPresent(Map<String, Object> target, String ...
      method observationType (line 229) | private static String observationType(TraceSpanType type) {
      method observationLevel (line 250) | private static String observationLevel(TraceSpanStatus status) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/OpenTelemetryTraceExporter.java
  class OpenTelemetryTraceExporter (line 6) | public class OpenTelemetryTraceExporter extends AbstractOpenTelemetryTra...
    method OpenTelemetryTraceExporter (line 8) | public OpenTelemetryTraceExporter(OpenTelemetry openTelemetry) {
    method OpenTelemetryTraceExporter (line 12) | public OpenTelemetryTraceExporter(Tracer tracer) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/OpenTelemetryTraceSupport.java
  class OpenTelemetryTraceSupport (line 10) | final class OpenTelemetryTraceSupport {
    method OpenTelemetryTraceSupport (line 12) | private OpenTelemetryTraceSupport() {
    method applyCommonAttributes (line 15) | static void applyCommonAttributes(Span span, TraceSpan traceSpan) {
    method setAttribute (line 62) | static void setAttribute(Span span, String key, Object value) {
    method safeSegment (line 89) | static String safeSegment(String value) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/TraceConfig.java
  class TraceConfig (line 6) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/TraceExporter.java
  type TraceExporter (line 3) | public interface TraceExporter {
    method export (line 5) | void export(TraceSpan span);

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/TraceMasker.java
  type TraceMasker (line 3) | public interface TraceMasker {
    method mask (line 5) | String mask(String value);

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/TraceMetrics.java
  class TraceMetrics (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/TracePricing.java
  class TracePricing (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/TracePricingResolver.java
  type TracePricingResolver (line 3) | public interface TracePricingResolver {
    method resolve (line 5) | TracePricing resolve(String model);

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/TraceSpan.java
  class TraceSpan (line 9) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/TraceSpanEvent.java
  class TraceSpanEvent (line 10) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/TraceSpanStatus.java
  type TraceSpanStatus (line 3) | public enum TraceSpanStatus {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/trace/TraceSpanType.java
  type TraceSpanType (line 3) | public enum TraceSpanType {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/util/AgentInputItem.java
  class AgentInputItem (line 10) | public final class AgentInputItem {
    method AgentInputItem (line 12) | private AgentInputItem() {
    method inputText (line 15) | public static Map<String, Object> inputText(String text) {
    method inputImageUrl (line 22) | public static Map<String, Object> inputImageUrl(String url) {
    method userMessage (line 31) | public static Map<String, Object> userMessage(String text) {
    method userMessage (line 35) | public static Map<String, Object> userMessage(String text, String... i...
    method systemMessage (line 39) | public static Map<String, Object> systemMessage(String text) {
    method message (line 43) | public static Map<String, Object> message(String role, String text) {
    method message (line 53) | public static Map<String, Object> message(String role, String text, St...
    method functionCallOutput (line 72) | public static Map<String, Object> functionCallOutput(String callId, St...
    method assistantToolCallsMessage (line 80) | public static Map<String, Object> assistantToolCallsMessage(String tex...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/util/ResponseUtil.java
  class ResponseUtil (line 11) | public final class ResponseUtil {
    method ResponseUtil (line 13) | private ResponseUtil() {
    method extractOutputText (line 16) | public static String extractOutputText(Response response) {
    method extractToolCalls (line 37) | public static List<AgentToolCall> extractToolCalls(Response response) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/workflow/AgentNode.java
  type AgentNode (line 7) | public interface AgentNode {
    method execute (line 9) | AgentResult execute(WorkflowContext context, AgentRequest request) thr...
    method executeStream (line 11) | default void executeStream(WorkflowContext context, AgentRequest reque...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/workflow/AgentWorkflow.java
  type AgentWorkflow (line 8) | public interface AgentWorkflow {
    method run (line 10) | AgentResult run(AgentSession session, AgentRequest request) throws Exc...
    method runStream (line 12) | void runStream(AgentSession session, AgentRequest request, AgentListen...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/workflow/RuntimeAgentNode.java
  class RuntimeAgentNode (line 8) | public class RuntimeAgentNode implements AgentNode, WorkflowResultAware {
    method RuntimeAgentNode (line 13) | public RuntimeAgentNode(AgentSession session) {
    method execute (line 17) | @Override
    method executeStream (line 23) | @Override
    method getLastResult (line 28) | @Override

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/workflow/SequentialWorkflow.java
  class SequentialWorkflow (line 11) | public class SequentialWorkflow implements AgentWorkflow {
    method addNode (line 15) | public SequentialWorkflow addNode(AgentNode node) {
    method getNodes (line 22) | public List<AgentNode> getNodes() {
    method run (line 26) | @Override
    method runStream (line 32) | @Override
    method executeNodes (line 38) | private AgentResult executeNodes(WorkflowContext context, AgentRequest...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/workflow/StateCondition.java
  type StateCondition (line 6) | public interface StateCondition {
    method matches (line 8) | boolean matches(WorkflowContext context, AgentRequest request, AgentRe...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/workflow/StateGraphWorkflow.java
  class StateGraphWorkflow (line 13) | public class StateGraphWorkflow implements AgentWorkflow {
    method addNode (line 21) | public StateGraphWorkflow addNode(String nodeId, AgentNode node) {
    method start (line 29) | public StateGraphWorkflow start(String nodeId) {
    method maxSteps (line 34) | public StateGraphWorkflow maxSteps(int maxSteps) {
    method addTransition (line 41) | public StateGraphWorkflow addTransition(String from, String to) {
    method addTransition (line 45) | public StateGraphWorkflow addTransition(String from, String to, StateC...
    method addEdge (line 54) | public StateGraphWorkflow addEdge(String from, String to) {
    method addConditionalEdges (line 58) | public StateGraphWorkflow addConditionalEdges(String from, StateRouter...
    method addConditionalEdges (line 62) | public StateGraphWorkflow addConditionalEdges(String from, StateRouter...
    method run (line 74) | @Override
    method runStream (line 80) | @Override
    method executeGraph (line 86) | private AgentResult executeGraph(WorkflowContext context, AgentRequest...
    method resolveNext (line 128) | private String resolveNext(String currentNodeId, WorkflowContext conte...
    class ConditionalEdges (line 156) | private static class ConditionalEdges {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/workflow/StateRouter.java
  type StateRouter (line 6) | public interface StateRouter {
    method route (line 8) | String route(WorkflowContext context, AgentRequest request, AgentResul...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/workflow/StateTransition.java
  class StateTransition (line 8) | @Data

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/workflow/WorkflowAgent.java
  class WorkflowAgent (line 8) | public class WorkflowAgent {
    method WorkflowAgent (line 13) | public WorkflowAgent(AgentWorkflow workflow, AgentSession session) {
    method run (line 18) | public AgentResult run(AgentRequest request) throws Exception {
    method runStream (line 22) | public void runStream(AgentRequest request, AgentListener listener) th...

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/workflow/WorkflowContext.java
  class WorkflowContext (line 14) | @Data
    method put (line 25) | public void put(String key, Object value) {
    method get (line 29) | public Object get(String key) {
    method createResultEvent (line 33) | public AgentEvent createResultEvent(AgentResult result) {

FILE: ai4j-agent/src/main/java/io/github/lnyocly/ai4j/agent/workflow/WorkflowResultAware.java
  type WorkflowResultAware (line 5) | public interface WorkflowResultAware {
    method getLastResult (line 7) | AgentResult getLastResult();

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentFlowTraceBridgeTest.java
  class AgentFlowTraceBridgeTest (line 20) | public class AgentFlowTraceBridgeTest {
    method test_bridge_exports_agentflow_chat_span (line 22) | @Test
    method test_bridge_exports_error_span (line 79) | @Test

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentMemoryTest.java
  class AgentMemoryTest (line 10) | public class AgentMemoryTest {
    method test_windowed_compression (line 12) | @Test

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentRuntimeTest.java
  class AgentRuntimeTest (line 28) | public class AgentRuntimeTest {
    method test_tool_loop_and_output (line 30) | @Test
    method test_stream_run_publishes_reasoning_and_text_before_tool_call (line 57) | @Test
    method test_invalid_tool_call_is_reported_without_execution (line 124) | @Test
    method test_stream_run_publishes_model_retry_event (line 170) | @Test
    method test_zero_max_steps_means_unlimited (line 213) | @Test
    method resultWithText (line 236) | private AgentModelResult resultWithText(String text) {
    method resultWithToolCall (line 244) | private AgentModelResult resultWithToolCall(String callId, String name...
    class QueueModelClient (line 257) | private static class QueueModelClient implements AgentModelClient {
      method QueueModelClient (line 260) | private QueueModelClient(Deque<AgentModelResult> queue) {
      method create (line 264) | @Override
      method createStream (line 269) | @Override
    class CountingToolExecutor (line 275) | private static class CountingToolExecutor implements ToolExecutor {
      method execute (line 278) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentTeamAgentAdapterTest.java
  class AgentTeamAgentAdapterTest (line 29) | public class AgentTeamAgentAdapterTest {
    method shouldBuildTeamAsStandardAgentAndRun (line 31) | @Test
    method shouldEmitTeamTaskEventsWhenRunningStream (line 62) | @Test
    method shouldPreserveTeamPersistenceSettingsWhenBuildingStandardAgent (line 103) | @Test
    method firstEvent (line 156) | private static AgentEvent firstEvent(List<AgentEvent> events, AgentEve...
    method newAgent (line 168) | private static Agent newAgent(String model, AgentModelClient client) {
    method textResult (line 175) | private static AgentModelResult textResult(String text) {
    class ScriptedModelClient (line 183) | private static class ScriptedModelClient implements AgentModelClient {
      method enqueue (line 186) | private void enqueue(AgentModelResult result) {
      method create (line 190) | @Override
      method createStream (line 195) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentTeamPersistenceTest.java
  class AgentTeamPersistenceTest (line 28) | public class AgentTeamPersistenceTest {
    method shouldPersistAndRestoreTeamStateFromStorageDirectory (line 33) | @Test
    method buildTeam (line 68) | private AgentTeam buildTeam(Path root, String teamId) {
    method newAgent (line 98) | private Agent newAgent(String model, AgentModelClient client) {
    method textResult (line 105) | private AgentModelResult textResult(String text) {
    class ScriptedModelClient (line 113) | private static class ScriptedModelClient implements AgentModelClient {
      method enqueue (line 116) | private void enqueue(AgentModelResult result) {
      method create (line 120) | @Override
      method createStream (line 125) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentTeamProjectDeliveryExampleTest.java
  class AgentTeamProjectDeliveryExampleTest (line 40) | public class AgentTeamProjectDeliveryExampleTest {
    method test_project_delivery_team_example (line 42) | @Test
    method projectPlanner (line 122) | private static AgentTeamPlanner projectPlanner() {
    method projectSynthesizer (line 160) | private static AgentTeamSynthesizer projectSynthesizer() {
    method member (line 185) | private static AgentTeamMember member(String id,
    method hasMessage (line 197) | private static boolean hasMessage(List<AgentTeamMessage> messages,
    method equals (line 217) | private static boolean equals(String left, String right) {
    method safe (line 224) | private static String safe(String value) {
    method textResult (line 228) | private static AgentModelResult textResult(String text) {
    method toolCallResult (line 236) | private static AgentModelResult toolCallResult(List<AgentToolCall> cal...
    method toolCall (line 244) | private static AgentToolCall toolCall(String name, String arguments) {
    method printResult (line 253) | private static void printResult(AgentTeamResult result) {
    class ScriptedModelClient (line 282) | private static class ScriptedModelClient implements AgentModelClient {
      method enqueue (line 285) | void enqueue(AgentModelResult result) {
      method create (line 289) | @Override
      method createStream (line 294) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentTeamTaskBoardTest.java
  class AgentTeamTaskBoardTest (line 14) | public class AgentTeamTaskBoardTest {
    method test_claim_release_reassign_and_dependency_flow (line 16) | @Test
    method test_recover_timed_out_claims (line 59) | @Test

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentTeamTest.java
  class AgentTeamTest (line 30) | public class AgentTeamTest {
    method test_team_plan_delegate_synthesize (line 32) | @Test
    method test_team_parallel_dispatch (line 72) | @Test
    method test_team_planner_fallback_broadcast (line 100) | @Test
    method test_team_dependency_and_message_bus (line 135) | @Test
    method test_team_plan_approval_rejected (line 167) | @Test
    method test_team_dynamic_member_registration_and_hooks (line 194) | @Test
    method test_team_message_controls_direct_and_broadcast (line 252) | @Test
    method test_team_list_task_states_after_run (line 271) | @Test
    method test_team_member_tools_can_message_and_heartbeat (line 296) | @Test
    method test_team_single_lead_agent_defaults_planner_and_synthesizer (line 348) | @Test
    method newAgent (line 370) | private static Agent newAgent(String model, AgentModelClient client) {
    method textResult (line 377) | private static AgentModelResult textResult(String text) {
    method toolCallResult (line 385) | private static AgentModelResult toolCallResult(List<AgentToolCall> cal...
    method toolCall (line 393) | private static AgentToolCall toolCall(String name, String arguments) {
    method hasToolNamed (line 402) | private static boolean hasToolNamed(List<Object> tools, String name) {
    class ScriptedModelClient (line 418) | private static class ScriptedModelClient implements AgentModelClient {
      method enqueue (line 422) | private void enqueue(AgentModelResult result) {
      method create (line 426) | @Override
      method createStream (line 432) | @Override
    class ConcurrentModelClient (line 438) | private static class ConcurrentModelClient implements AgentModelClient {
      method ConcurrentModelClient (line 444) | private ConcurrentModelClient(long sleepMs, String output) {
      method create (line 449) | @Override
      method createStream (line 463) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentTeamUsageTest.java
  class AgentTeamUsageTest (line 26) | public class AgentTeamUsageTest extends ZhipuAgentTestSupport {
    method test_team_with_deterministic_plan_and_real_members (line 28) | @Test
    method test_team_dynamic_member_and_message_bus (line 93) | @Test
    method createRoleAgent (line 145) | private Agent createRoleAgent(String systemPrompt, String instructions) {
    method runTeamWithRetry (line 156) | private AgentTeamResult runTeamWithRetry(AgentTeam team, String object...
    method allTasksCompleted (line 167) | private boolean allTasksCompleted(List<AgentTeamTaskState> states) {
    method describeTaskStates (line 179) | private String describeTaskStates(List<AgentTeamTaskState> states) {

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentTraceListenerTest.java
  class AgentTraceListenerTest (line 22) | public class AgentTraceListenerTest {
    method test_trace_listener_collects_spans (line 24) | @Test
    method test_trace_listener_captures_reasoning_handoff_team_and_memory_events (line 57) | @Test
    method test_trace_listener_captures_model_usage_cost_and_duration_metrics (line 106) | @Test
    method findSpan (line 151) | private TraceSpan findSpan(List<TraceSpan> spans, TraceSpanType type) {
    method retryPayload (line 160) | private Map<String, Object> retryPayload() {
    method handoffPayload (line 168) | private Map<String, Object> handoffPayload(String status, String error) {
    method teamPayload (line 179) | private Map<String, Object> teamPayload(String status, String error) {
    method messagePayload (line 188) | private Map<String, Object> messagePayload() {
    method compactPayload (line 195) | private Map<String, Object> compactPayload() {
    method modelResponsePayload (line 202) | private Map<String, Object> modelResponsePayload() {
    method event (line 217) | private AgentEvent event(AgentEventType type, Integer step, String mes...

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentTraceUsageTest.java
  class AgentTraceUsageTest (line 17) | public class AgentTraceUsageTest extends ZhipuAgentTestSupport {
    method test_trace_for_react_runtime_with_real_model (line 19) | @Test
    method test_trace_mask_and_truncate_config (line 44) | @Test

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentWorkflowTest.java
  class AgentWorkflowTest (line 12) | public class AgentWorkflowTest {
    method test_sequential_workflow_passes_output (line 14) | @Test
    class StaticNode (line 24) | private static class StaticNode implements AgentNode {
      method StaticNode (line 27) | private StaticNode(String output) {
      method execute (line 31) | @Override
    class EchoNode (line 37) | private static class EchoNode implements AgentNode {
      method execute (line 38) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/AgentWorkflowUsageTest.java
  class AgentWorkflowUsageTest (line 17) | public class AgentWorkflowUsageTest extends ZhipuAgentTestSupport {
    method test_sequential_workflow_with_real_agents (line 19) | @Test
    method test_state_graph_workflow_with_router (line 49) | @Test

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/ChatModelClientTest.java
  class ChatModelClientTest (line 31) | public class ChatModelClientTest {
    method test_stream_preserves_reasoning_text_and_tool_calls (line 33) | @Test
    method test_stream_preserves_invalid_coding_tool_calls_for_runtime_validation (line 66) | @Test
    method test_stream_aggregates_minimax_style_fragmented_tool_calls (line 82) | @Test
    method test_stream_propagates_stream_execution_options (line 101) | @Test
    method test_stream_surfaces_http_error_payload_when_sse_failure_has_no_throwable (line 126) | @Test
    method test_create_stores_assistant_tool_calls_in_memory_items (line 147) | @Test
    method test_create_rehydrates_assistant_tool_calls_before_tool_output (line 173) | @Test
    class FakeChatService (line 209) | private static class FakeChatService implements IChatService {
      method chatCompletion (line 212) | @Override
      method chatCompletion (line 217) | @Override
      method chatCompletionStream (line 222) | @Override
      method chatCompletionStream (line 235) | @Override
    class FakeInvalidBashChatService (line 241) | private static class FakeInvalidBashChatService implements IChatService {
      method chatCompletion (line 242) | @Override
      method chatCompletion (line 247) | @Override
      method chatCompletionStream (line 252) | @Override
      method chatCompletionStream (line 262) | @Override
    class FakeStreamingErrorChatService (line 268) | private static class FakeStreamingErrorChatService implements IChatSer...
      method chatCompletion (line 269) | @Override
      method chatCompletion (line 274) | @Override
      method chatCompletionStream (line 279) | @Override
      method chatCompletionStream (line 295) | @Override
    class CapturingChatService (line 301) | private static class CapturingChatService implements IChatService {
      method chatCompletion (line 305) | @Override
      method chatCompletion (line 311) | @Override
      method chatCompletionStream (line 317) | @Override
      method chatCompletionStream (line 322) | @Override
      method response (line 327) | private ChatCompletionResponse response() {
    class FakeFragmentedMiniMaxChatService (line 339) | private static class FakeFragmentedMiniMaxChatService implements IChat...
      method chatCompletion (line 340) | @Override
      method chatCompletion (line 345) | @Override
      method chatCompletionStream (line 350) | @Override
      method chatCompletionStream (line 362) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/CodeActAgentUsageTest.java
  class CodeActAgentUsageTest (line 20) | public class CodeActAgentUsageTest extends ZhipuAgentTestSupport {
    method test_codeact_basic_js_execution (line 22) | @Test
    method test_codeact_react_finalize_flow_without_external_tool (line 46) | @Test
    method isNashornAvailable (line 71) | private boolean isNashornAvailable() {
    method runWithRetry (line 76) | private AgentResult runWithRetry(Agent agent, AgentRequest request, in...
    method isRetryable (line 91) | private boolean isRetryable(Throwable throwable) {

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/CodeActPythonExecutorTest.java
  class CodeActPythonExecutorTest (line 13) | public class CodeActPythonExecutorTest {
    method test_python_executor_with_tool (line 15) | @Test
    method isGraalPyAvailable (line 38) | private boolean isGraalPyAvailable() {

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/CodeActRuntimeTest.java
  class CodeActRuntimeTest (line 32) | public class CodeActRuntimeTest {
    method init (line 36) | @Before
    method test_codeact_with_tool (line 70) | @Test
    method buildEventPublisher (line 97) | private AgentEventPublisher buildEventPublisher() {
    method logToolCall (line 103) | private void logToolCall(AgentEvent event) {

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/CodeActRuntimeWithTraceTest.java
  class CodeActRuntimeWithTraceTest (line 32) | public class CodeActRuntimeWithTraceTest {
    method init (line 36) | @Before
    method test_codeact_with_trace (line 71) | @Test
    method isNashornAvailable (line 98) | private boolean isNashornAvailable() {

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/DoubaoAgentTeamBestPracticeTest.java
  class DoubaoAgentTeamBestPracticeTest (line 45) | public class DoubaoAgentTeamBestPracticeTest {
    method init (line 53) | @Before
    method test_doubao_agent_team_best_practice (line 85) | @Test

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/DoubaoAgentWorkflowTest.java
  class DoubaoAgentWorkflowTest (line 29) | public class DoubaoAgentWorkflowTest {
    method init (line 33) | @Before
    method test_doubao_agent_workflow (line 65) | @Test

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/DoubaoProjectTeamAgentTeamsTest.java
  class DoubaoProjectTeamAgentTeamsTest (line 37) | public class DoubaoProjectTeamAgentTeamsTest {
    method init (line 46) | @Before
    method test_project_delivery_team_with_doubao (line 77) | @Test
    method createRoleAgent (line 174) | private Agent createRoleAgent(String systemPrompt, String instructions) {

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/FileAgentTeamStateStoreTest.java
  class FileAgentTeamStateStoreTest (line 16) | public class FileAgentTeamStateStoreTest {
    method shouldSaveLoadListAndDeleteState (line 21) | @Test
    method shouldPersistMailboxAcrossInstances (line 49) | @Test

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/HandoffPolicyTest.java
  class HandoffPolicyTest (line 21) | public class HandoffPolicyTest {
    method testAllowedToolsPolicyDeniesUnexpectedSubagent (line 23) | @Test
    method testDenyCanFallbackToPrimaryExecutor (line 51) | @Test
    method testRetryRecoversTransientSubagentFailure (line 69) | @Test
    method testTimeoutCanFallbackToPrimaryExecutor (line 104) | @Test
    method testInputFilterCanRewriteDelegatedArguments (line 144) | @Test
    method testNestedHandoffBlockedByMaxDepth (line 188) | @Test
    method staticOutputAgent (line 231) | private Agent staticOutputAgent(String output) {
    method queueModelClient (line 238) | private QueueModelClient queueModelClient(io.github.lnyocly.ai4j.agent...
    method textResult (line 242) | private io.github.lnyocly.ai4j.agent.model.AgentModelResult textResult...
    method toolCallResult (line 250) | private io.github.lnyocly.ai4j.agent.model.AgentModelResult toolCallRe...
    class QueueModelClient (line 262) | private static class QueueModelClient implements io.github.lnyocly.ai4...
      method QueueModelClient (line 265) | private QueueModelClient(List<io.github.lnyocly.ai4j.agent.model.Age...
      method create (line 269) | @Override
      method createStream (line 274) | @Override
    class NoopSubAgentRegistry (line 281) | private static class NoopSubAgentRegistry implements SubAgentRegistry {
      method NoopSubAgentRegistry (line 284) | private NoopSubAgentRegistry(String toolName) {
      method getTools (line 288) | @Override
      method supports (line 293) | @Override
      method execute (line 298) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/MinimaxAgentTeamTravelUsageTest.java
  class MinimaxAgentTeamTravelUsageTest (line 36) | public class MinimaxAgentTeamTravelUsageTest {
    method setupMinimaxClient (line 43) | @Before
    method test_travel_demo_delivery_team_with_minimax (line 63) | @Test
    method member (line 192) | private AgentTeamMember member(String id,
    method createHttpClient (line 213) | private OkHttpClient createHttpClient() {
    method renderSummary (line 225) | private String renderSummary(String objective, List<AgentTeamMemberRes...
    method appendSection (line 247) | private void appendSection(StringBuilder builder, String title, String...
    method allTasksCompleted (line 252) | private boolean allTasksCompleted(List<AgentTeamTaskState> states) {
    method describeTaskStates (line 264) | private String describeTaskStates(List<AgentTeamTaskState> states) {
    method printResult (line 290) | private void printResult(AgentTeamResult result) {
    method callWithProviderGuard (line 325) | private <T> T callWithProviderGuard(ThrowingSupplier<T> supplier) thro...
    method skipIfProviderUnavailable (line 334) | private void skipIfProviderUnavailable(Throwable throwable) {
    method isProviderUnavailable (line 340) | private boolean isProviderUnavailable(Throwable throwable) {
    method extractRootMessage (line 364) | private String extractRootMessage(Throwable throwable) {
    method readValue (line 374) | private String readValue(String envKey, String propertyKey) {
    method safe (line 382) | private String safe(String value) {
    method isBlank (line 386) | private boolean isBlank(String value) {
    type ThrowingSupplier (line 390) | @FunctionalInterface
      method get (line 392) | T get() throws Exception;

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/NashornCodeExecutorTest.java
  class NashornCodeExecutorTest (line 15) | public class NashornCodeExecutorTest {
    method test_nashorn_executor_with_tool_alias (line 17) | @Test
    method test_nashorn_parses_json_tool_result (line 39) | @Test
    method test_nashorn_uses_return_value_when_codeact_result_not_set (line 60) | @Test
    method test_nashorn_rejects_python_language (line 74) | @Test
    method isNashornAvailable (line 86) | private boolean isNashornAvailable() {

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/ReActAgentUsageTest.java
  class ReActAgentUsageTest (line 17) | public class ReActAgentUsageTest extends ZhipuAgentTestSupport {
    method test_react_agent_basic_run_with_real_model (line 19) | @Test
    method test_react_agent_parallel_tool_calls_and_event_lifecycle (line 37) | @Test

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/ResponsesModelClientTest.java
  class ResponsesModelClientTest (line 15) | public class ResponsesModelClientTest {
    method test_stream_propagates_stream_execution_options (line 17) | @Test
    class CapturingResponsesService (line 42) | private static final class CapturingResponsesService implements IRespo...
      method create (line 45) | @Override
      method create (line 50) | @Override
      method createStream (line 55) | @Override
      method createStream (line 60) | @Override
      method retrieve (line 65) | @Override
      method retrieve (line 70) | @Override
      method delete (line 75) | @Override
      method delete (line 80) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/StateGraphWorkflowTest.java
  class StateGraphWorkflowTest (line 33) | public class StateGraphWorkflowTest {
    method init (line 37) | @Before
    method test_branching_route (line 72) | @Test
    method test_loop_route (line 87) | @Test
    method test_state_graph_with_agents (line 109) | @Test
    class StaticNode (line 163) | private static class StaticNode implements AgentNode {
      method StaticNode (line 166) | private StaticNode(String output) {
      method execute (line 170) | @Override
    class CounterNode (line 176) | private static class CounterNode implements AgentNode {
      method CounterNode (line 179) | private CounterNode(AtomicInteger counter) {
      method execute (line 183) | @Override
    class NamedNode (line 191) | private static class NamedNode implements AgentNode {
      method NamedNode (line 195) | private NamedNode(String name, AgentNode delegate) {
      method execute (line 200) | @Override
    class RoutingAgentNode (line 214) | private static class RoutingAgentNode implements AgentNode {
      method RoutingAgentNode (line 217) | private RoutingAgentNode(AgentSession session) {
      method execute (line 221) | @Override
    class RuntimeAgentNode (line 237) | private static class RuntimeAgentNode implements AgentNode {
      method RuntimeAgentNode (line 240) | private RuntimeAgentNode(AgentSession session) {
      method execute (line 244) | @Override
    class FormatAgentNode (line 250) | private static class FormatAgentNode implements AgentNode {
      method FormatAgentNode (line 253) | private FormatAgentNode(AgentSession session) {
      method execute (line 257) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/SubAgentParallelFallbackTest.java
  class SubAgentParallelFallbackTest (line 29) | public class SubAgentParallelFallbackTest {
    method test_parallel_subagents_with_fallback_policy (line 31) | @Test
    method toResultMap (line 93) | private static Map<String, String> toResultMap(List<AgentToolResult> t...
    method textResult (line 104) | private static AgentModelResult textResult(String text) {
    method toolCallsResult (line 112) | private static AgentModelResult toolCallsResult(List<AgentToolCall> ca...
    class ScriptedModelClient (line 119) | private static class ScriptedModelClient implements AgentModelClient {
      method enqueue (line 122) | private void enqueue(AgentModelResult result) {
      method create (line 126) | @Override
      method createStream (line 131) | @Override
    class TimedSubAgentModelClient (line 137) | private static class TimedSubAgentModelClient implements AgentModelCli...
      method TimedSubAgentModelClient (line 143) | private TimedSubAgentModelClient(ConcurrencyTracker tracker, long sl...
      method create (line 150) | @Override
      method createStream (line 168) | @Override
    class ConcurrencyTracker (line 174) | private static class ConcurrencyTracker {

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/SubAgentRuntimeTest.java
  class SubAgentRuntimeTest (line 32) | public class SubAgentRuntimeTest {
    method testSubagentToolDelegationAndExposure (line 34) | @Test
    method testParallelSubagentExecutionForCodexStyleDelegation (line 72) | @Test
    method testSubagentHandoffEventsArePublished (line 120) | @Test
    method testTeamSubagentPublishesTeamTaskEventsToParent (line 177) | @Test
    method firstEvent (line 249) | private static AgentEvent firstEvent(List<AgentEvent> events, AgentEve...
    method firstEventByStatus (line 261) | private static AgentEvent firstEventByStatus(List<AgentEvent> events, ...
    method hasTool (line 279) | private static boolean hasTool(List<Object> tools, String name) {
    method resultWithText (line 294) | private static AgentModelResult resultWithText(String text) {
    method resultWithToolCall (line 302) | private static AgentModelResult resultWithToolCall(String callId, Stri...
    method resultWithToolCalls (line 313) | private static AgentModelResult resultWithToolCalls(List<AgentToolCall...
    class ScriptedModelClient (line 320) | private static class ScriptedModelClient implements AgentModelClient {
      method enqueue (line 324) | private void enqueue(AgentModelResult result) {
      method create (line 328) | @Override
      method createStream (line 334) | @Override
    class ConcurrentModelClient (line 340) | private static class ConcurrentModelClient implements AgentModelClient {
      method ConcurrentModelClient (line 346) | private ConcurrentModelClient(long sleepMs, String output) {
      method create (line 351) | @Override
      method createStream (line 365) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/SubAgentUsageTest.java
  class SubAgentUsageTest (line 17) | public class SubAgentUsageTest extends ZhipuAgentTestSupport {
    method test_subagent_delegation_with_real_llm (line 19) | @Test
    method test_handoff_policy_denied_with_fallback_executor (line 54) | @Test

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/ToolUtilExecutorRestrictionTest.java
  class ToolUtilExecutorRestrictionTest (line 9) | public class ToolUtilExecutorRestrictionTest {
    method testRejectsUnknownTool (line 11) | @Test(expected = IllegalArgumentException.class)

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/UniversalAgentUsageTest.java
  class UniversalAgentUsageTest (line 16) | public class UniversalAgentUsageTest extends ZhipuAgentTestSupport {
    method test_basic_agent_build_and_run (line 18) | @Test
    method test_advanced_parameters_and_session_memory (line 36) | @Test
    method test_stream_mode_with_real_chat_model (line 73) | @Test

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/WeatherAgentWorkflowTest.java
  class WeatherAgentWorkflowTest (line 33) | public class WeatherAgentWorkflowTest {
    method init (line 37) | @Before
    method test_weather_workflow (line 69) | @Test
    class NamedNode (line 103) | private static class NamedNode implements AgentNode {
      method NamedNode (line 107) | private NamedNode(String name, AgentNode delegate) {
      method execute (line 112) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/agent/support/ZhipuAgentTestSupport.java
  class ZhipuAgentTestSupport (line 19) | public abstract class ZhipuAgentTestSupport {
    method setupZhipuAiService (line 27) | @Before
    method chatModelClient (line 68) | protected ChatModelClient chatModelClient() {
    method callWithProviderGuard (line 72) | protected <T> T callWithProviderGuard(ThrowingSupplier<T> supplier) th...
    method skipIfProviderUnavailable (line 81) | protected void skipIfProviderUnavailable(Throwable throwable) {
    method isProviderUnavailable (line 88) | private boolean isProviderUnavailable(Throwable throwable) {
    method extractRootMessage (line 113) | private String extractRootMessage(Throwable throwable) {
    type ThrowingSupplier (line 124) | @FunctionalInterface
      method get (line 126) | T get() throws Exception;

FILE: ai4j-agent/src/test/java/io/github/lnyocly/ai4j/agent/flowgram/FlowGramRuntimeServiceTest.java
  class FlowGramRuntimeServiceTest (line 31) | public class FlowGramRuntimeServiceTest {
    method shouldValidateWorkflowShape (line 33) | @Test
    method shouldRunSimpleStartLlmEndWorkflow (line 55) | @Test
    method shouldRouteConditionBranch (line 90) | @Test
    method shouldAggregateLoopOutputs (line 120) | @Test
    method shouldCancelTask (line 155) | @Test
    method shouldExposeWorkflowFailureReasonInResultAndReport (line 186) | @Test
    method shouldPublishRuntimeListenerEventsForSuccessfulTask (line 222) | @Test
    method shouldRunAi4jBackedLlmNodeRunner (line 275) | @Test
    method awaitResult (line 310) | private static FlowGramTaskResultOutput awaitResult(FlowGramRuntimeSer...
    method waitForProcessing (line 322) | private static void waitForProcessing(FlowGramRuntimeService service, ...
    method awaitEvent (line 333) | private static void awaitEvent(List<FlowGramRuntimeEvent> events, Flow...
    method snapshot (line 346) | private static List<FlowGramRuntimeEvent> snapshot(List<FlowGramRuntim...
    method node (line 352) | private static FlowGramNodeSchema node(String id, String type, Map<Str...
    method edge (line 361) | private static FlowGramEdgeSchema edge(String source, String target) {
    method edge (line 368) | private static FlowGramEdgeSchema edge(String source, String target, S...
    method startData (line 376) | private static Map<String, Object> startData() {
    method startNumberData (line 380) | private static Map<String, Object> startNumberData() {
    method startCitiesData (line 384) | private static Map<String, Object> startCitiesData() {
    method llmData (line 388) | private static Map<String, Object> llmData(Map<String, Object> promptV...
    method endData (line 403) | private static Map<String, Object> endData(Map<String, Object> resultV...
    method endArrayData (line 410) | private static Map<String, Object> endArrayData(Map<String, Object> re...
    method conditionData (line 417) | private static Map<String, Object> conditionData() {
    method loopData (line 428) | private static Map<String, Object> loopData() {
    method stringSchema (line 437) | private static Map<String, Object> stringSchema() {
    method numberSchema (line 441) | private static Map<String, Object> numberSchema() {
    method objectSchema (line 445) | private static Map<String, Object> objectSchema(List<String> required,...
    method property (line 459) | private static Map<String, Object> property(String name, Map<String, O...
    method required (line 463) | private static List<String> required(String... names) {
    method ref (line 467) | private static Map<String, Object> ref(String... path) {
    method constant (line 471) | private static Map<String, Object> constant(Object content) {
    method mapOf (line 475) | private static Map<String, Object> mapOf(Object... keyValues) {
    class EchoRunner (line 483) | private static final class EchoRunner implements FlowGramLlmNodeRunner {
      method run (line 484) | @Override
    class SlowRunner (line 490) | private static final class SlowRunner implements FlowGramLlmNodeRunner {
      method run (line 491) | @Override
    class FailingRunner (line 500) | private static final class FailingRunner implements FlowGramLlmNodeRun...
      method run (line 501) | @Override

FILE: ai4j-agent/src/test/java/io/github/lnyocly/ai4j/agent/memory/JdbcAgentMemoryTest.java
  class JdbcAgentMemoryTest (line 15) | public class JdbcAgentMemoryTest {
    method shouldPersistAgentMemoryAcrossInstances (line 17) | @Test
    method shouldIncludeSummaryInMergedItems (line 40) | @Test
    method shouldSupportSnapshotRestoreAndClear (line 57) | @Test
    method jdbcUrl (line 79) | private String jdbcUrl(String suffix) {

FILE: ai4j-agent/src/test/java/io/github/lnyocly/ai4j/agent/model/ChatModelClientTest.java
  class ChatModelClientTest (line 14) | public class ChatModelClientTest {
    method createShouldEnableToolCallPassThroughForAgentTools (line 16) | @Test
    method testTool (line 51) | private Tool testTool(String name) {

FILE: ai4j-agent/src/test/java/io/github/lnyocly/ai4j/agent/trace/LangfuseTraceExporterTest.java
  class LangfuseTraceExporterTest (line 9) | public class LangfuseTraceExporterTest {
    method test_langfuse_projection_for_model_span (line 11) | @Test

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/Ai4jCli.java
  class Ai4jCli (line 23) | public class Ai4jCli {
    method Ai4jCli (line 28) | public Ai4jCli() {
    method Ai4jCli (line 32) | Ai4jCli(CodingCliAgentFactory agentFactory, Path currentDirectory) {
    method run (line 37) | public int run(String[] args, InputStream in, OutputStream out, Output...
    method run (line 41) | int run(String[] args,
    method printHelp (line 89) | private void printHelp(TerminalIO terminal) {
    method asTuiArguments (line 111) | private List<String> asTuiArguments(List<String> arguments) {
    method createTerminal (line 121) | private TerminalIO createTerminal(InputStream in, OutputStream out, Ou...
    method closeQuietly (line 131) | private void closeQuietly(TerminalIO terminal) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/Ai4jCliMain.java
  class Ai4jCliMain (line 3) | public final class Ai4jCliMain {
    method Ai4jCliMain (line 5) | private Ai4jCliMain() {
    method main (line 8) | public static void main(String[] args) {
    method configureLogging (line 16) | private static void configureLogging(String[] args) {
    method hasVerboseFlag (line 25) | private static boolean hasVerboseFlag(String[] args) {
    method setIfAbsent (line 37) | private static void setIfAbsent(String key, String value) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/ApprovalMode.java
  type ApprovalMode (line 5) | public enum ApprovalMode {
    method ApprovalMode (line 12) | ApprovalMode(String value) {
    method getValue (line 16) | public String getValue() {
    method parse (line 20) | public static ApprovalMode parse(String raw) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/CliProtocol.java
  type CliProtocol (line 7) | public enum CliProtocol {
    method CliProtocol (line 13) | CliProtocol(String value) {
    method getValue (line 17) | public String getValue() {
    method parse (line 21) | public static CliProtocol parse(String value) {
    method resolveConfigured (line 31) | public static CliProtocol resolveConfigured(String value, PlatformType...
    method defaultProtocol (line 39) | public static CliProtocol defaultProtocol(PlatformType provider, Strin...
    method normalize (line 53) | private static String normalize(String value) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/CliUiMode.java
  type CliUiMode (line 3) | public enum CliUiMode {
    method CliUiMode (line 9) | CliUiMode(String value) {
    method getValue (line 13) | public String getValue() {
    method parse (line 17) | public static CliUiMode parse(String value) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/SlashCommandController.java
  class SlashCommandController (line 27) | public final class SlashCommandController implements Completer {
    method run (line 30) | @Override
    method get (line 140) | @Override
    method get (line 147) | @Override
    method get (line 154) | @Override
    method get (line 161) | @Override
    method get (line 168) | @Override
    method get (line 175) | @Override
    method get (line 182) | @Override
    method SlashCommandController (line 190) | public SlashCommandController(CustomCommandRegistry customCommandRegis...
    method setSessionManager (line 195) | public void setSessionManager(CodingSessionManager sessionManager) {
    method setProcessCandidateSupplier (line 199) | public void setProcessCandidateSupplier(Supplier<List<ProcessCompletio...
    method setProfileCandidateSupplier (line 212) | public void setProfileCandidateSupplier(Supplier<List<String>> profile...
    method setModelCandidateSupplier (line 225) | public void setModelCandidateSupplier(Supplier<List<ModelCompletionCan...
    method setMcpServerCandidateSupplier (line 238) | public void setMcpServerCandidateSupplier(Supplier<List<String>> mcpSe...
    method setSkillCandidateSupplier (line 251) | public void setSkillCandidateSupplier(Supplier<List<String>> skillCand...
    method setAgentCandidateSupplier (line 264) | public void setAgentCandidateSupplier(Supplier<List<String>> agentCand...
    method setTeamCandidateSupplier (line 277) | public void setTeamCandidateSupplier(Supplier<List<String>> teamCandid...
    method setStatusRefresh (line 290) | public void setStatusRefresh(Runnable statusRefresh) {
    method configure (line 294) | public void configure(LineReader lineReader) {
    method complete (line 395) | @Override
    method suggest (line 403) | List<Candidate> suggest(String line, int cursor) {
    method exactCommandArgumentCandidates (line 472) | private List<Candidate> exactCommandArgumentCandidates(String command) {
    method openSlashMenu (line 516) | boolean openSlashMenu(LineReader lineReader) {
    method openCommandPalette (line 538) | private boolean openCommandPalette(LineReader lineReader) {
    method acceptLine (line 557) | private boolean acceptLine(LineReader lineReader) {
    method shouldExecuteRawInputOnEnter (line 580) | private boolean shouldExecuteRawInputOnEnter(String line) {
    method resolveSlashMenuAction (line 596) | SlashMenuAction resolveSlashMenuAction(String line, int cursor) {
    method resolveAcceptLineAction (line 607) | EnterAction resolveAcceptLineAction(String line) {
    method getPaletteSnapshot (line 611) | public PaletteSnapshot getPaletteSnapshot() {
    method movePaletteSelection (line 617) | void movePaletteSelection(int delta) {
    method acceptSlashSelection (line 629) | boolean acceptSlashSelection(LineReader lineReader, boolean alwaysAcce...
    method applySelectedValue (line 660) | private String applySelectedValue(String current, int cursor, String s...
    method shouldContinuePaletteAfterAccept (line 675) | private boolean shouldContinuePaletteAfterAccept(String replacement, P...
    method commandRequiresArgument (line 689) | private boolean commandRequiresArgument(String command) {
    method isExecutableRootCommand (line 701) | private boolean isExecutableRootCommand(String value) {
    method bindWidget (line 713) | private void bindWidget(LineReader lineReader, String widgetName, Stri...
    method bind (line 723) | private void bind(LineReader lineReader, String keymapName, Reference ...
    method wrapWidget (line 737) | private void wrapWidget(LineReader lineReader, String widgetName, Widg...
    method delegateAndRefreshSlashPalette (line 753) | private boolean delegateAndRefreshSlashPalette(LineReader lineReader, ...
    method delegateWidget (line 761) | private boolean delegateWidget(LineReader lineReader, String widgetNam...
    method navigateSlashPalette (line 772) | private boolean navigateSlashPalette(LineReader lineReader, int delta,...
    method refreshSlashPaletteIfNeeded (line 782) | private void refreshSlashPaletteIfNeeded(LineReader lineReader) {
    method syncSlashPalette (line 795) | private void syncSlashPalette(LineReader lineReader) {
    method updatePalette (line 813) | private void updatePalette(String query, List<Candidate> candidates) {
    method resolveSelectedIndex (line 836) | private int resolveSelectedIndex(List<PaletteItemSnapshot> items, Stri...
    method clearPalette (line 857) | private void clearPalette() {
    method getSelectedPaletteItem (line 863) | private PaletteItemSnapshot getSelectedPaletteItem() {
    method refreshStatusAndDisplay (line 872) | private void refreshStatusAndDisplay(LineReader lineReader) {
    method notifyStatusRefresh (line 881) | private void notifyStatusRefresh() {
    method rootCandidates (line 888) | private List<Candidate> rootCandidates(String partial) {
    method prefixCandidates (line 898) | private List<Candidate> prefixCandidates(String prefix, List<Candidate...
    method customCommandCandidates (line 920) | private List<Candidate> customCommandCandidates(String partial) {
    method themeCandidates (line 942) | private List<Candidate> themeCandidates(String partial) {
    method streamCandidates (line 956) | private List<Candidate> streamCandidates(String partial) {
    method experimentalCandidates (line 975) | private List<Candidate> experimentalCandidates(List<String> tokens, bo...
    method experimentalFeatureCandidates (line 994) | private List<Candidate> experimentalFeatureCandidates(String partial) {
    method describeExperimentalFeature (line 1013) | private String describeExperimentalFeature(String feature) {
    method experimentalToggleCandidates (line 1023) | private List<Candidate> experimentalToggleCandidates(String partial) {
    method teamCandidates (line 1042) | private List<Candidate> teamCandidates(List<String> tokens, boolean en...
    method teamActionCandidates (line 1082) | private List<Candidate> teamActionCandidates(String partial) {
    method teamIdCandidates (line 1093) | private List<Candidate> teamIdCandidates(String partial) {
    method teamMessageLimitCandidates (line 1117) | private List<Candidate> teamMessageLimitCandidates(String partial) {
    method describeTeamAction (line 1136) | private String describeTeamAction(String action) {
    method skillCandidates (line 1152) | private List<Candidate> skillCandidates(String partial) {
    method agentCandidates (line 1176) | private List<Candidate> agentCandidates(String partial) {
    method mcpCandidates (line 1200) | private List<Candidate> mcpCandidates(List<String> tokens, boolean end...
    method mcpActionCandidates (line 1226) | private List<Candidate> mcpActionCandidates(String partial) {
    method describeMcpAction (line 1237) | private String describeMcpAction(String action) {
    method mcpAddCandidates (line 1265) | private List<Candidate> mcpAddCandidates(List<String> tokens, boolean ...
    method mcpAddOptionCandidates (line 1287) | private List<Candidate> mcpAddOptionCandidates(String partial) {
    method mcpTransportCandidates (line 1301) | private List<Candidate> mcpTransportCandidates(String partial) {
    method mcpServerNameCandidates (line 1320) | private List<Candidate> mcpServerNameCandidates(String action, String ...
    method describeMcpServerAction (line 1344) | private String describeMcpServerAction(String action, String serverNam...
    method providerCandidates (line 1366) | private List<Candidate> providerCandidates(List<String> tokens, boolea...
    method isExactProviderAction (line 1397) | private boolean isExactProviderAction(String value) {
    method providerActionCandidates (line 1409) | private List<Candidate> providerActionCandidates(String partial) {
    method providerNameCandidates (line 1420) | private List<Candidate> providerNameCandidates(String action, String p...
    method describeProviderProfileAction (line 1450) | private String describeProviderProfileAction(String action, String pro...
    method providerDefaultCandidates (line 1463) | private List<Candidate> providerDefaultCandidates(String partial) {
    method providerMutationCandidates (line 1501) | private List<Candidate> providerMutationCandidates(String action, List...
    method providerMutationOptionCandidates (line 1539) | private List<Candidate> providerMutationOptionCandidates(String partia...
    method describeProviderMutationOption (line 1556) | private String describeProviderMutationOption(String option) {
    method isProviderMutationOption (line 1584) | private boolean isProviderMutationOption(String value) {
    method providerMutationValueCandidates (line 1596) | private List<Candidate> providerMutationValueCandidates(String option,...
    method providerTypeCandidates (line 1606) | private List<Candidate> providerTypeCandidates(String partial) {
    method providerProtocolCandidates (line 1625) | private List<Candidate> providerProtocolCandidates(String partial) {
    method addProviderProtocolCandidate (line 1632) | private void addProviderProtocolCandidate(List<Candidate> candidates, ...
    method modelCandidates (line 1647) | private List<Candidate> modelCandidates(String partial) {
    method sessionCandidates (line 1682) | private List<Candidate> sessionCandidates(String partial) {
    method processCandidates (line 1709) | private List<Candidate> processCandidates(List<String> tokens, boolean...
    method processSubcommandCandidates (line 1744) | private List<Candidate> processSubcommandCandidates(String partial) {
    method processIdCandidates (line 1761) | private List<Candidate> processIdCandidates(ProcessCommandSpec command...
    method processLimitCandidates (line 1783) | private List<Candidate> processLimitCandidates(ProcessCommandSpec comm...
    method findProcessCommandSpec (line 1803) | private ProcessCommandSpec findProcessCommandSpec(String value) {
    method commandCandidate (line 1815) | private Candidate commandCandidate(String value,
    method tokenFragment (line 1824) | private String tokenFragment(List<String> tokens, boolean endsWithSpac...
    method splitTokens (line 1834) | private List<String> splitTokens(String value) {
    method matches (line 1845) | private boolean matches(String candidate, String partial) {
    method firstNonBlank (line 1857) | private String firstNonBlank(String... values) {
    method isBlank (line 1869) | private boolean isBlank(String value) {
    method sameText (line 1873) | private boolean sameText(String left, String right) {
    class SlashCommandSpec (line 1880) | private static final class SlashCommandSpec {
      method SlashCommandSpec (line 1886) | private SlashCommandSpec(String command, String description, boolean...
    class ProcessCompletionCandidate (line 1893) | public static final class ProcessCompletionCandidate {
      method ProcessCompletionCandidate (line 1898) | public ProcessCompletionCandidate(String processId, String descripti...
      method getProcessId (line 1903) | public String getProcessId() {
      method getDescription (line 1907) | public String getDescription() {
    class ModelCompletionCandidate (line 1912) | public static final class ModelCompletionCandidate {
      method ModelCompletionCandidate (line 1917) | public ModelCompletionCandidate(String model, String description) {
      method getModel (line 1922) | public String getModel() {
      method getDescription (line 1926) | public String getDescription() {
    class ProcessCommandSpec (line 1931) | private static final class ProcessCommandSpec {
      method ProcessCommandSpec (line 1938) | private ProcessCommandSpec(String name, String description, boolean ...
    class PaletteSnapshot (line 1946) | public static final class PaletteSnapshot {
      method PaletteSnapshot (line 1953) | private PaletteSnapshot(boolean open, String query, int selectedInde...
      method closed (line 1962) | public static PaletteSnapshot closed() {
      method isOpen (line 1966) | public boolean isOpen() {
      method getQuery (line 1970) | public String getQuery() {
      method getSelectedIndex (line 1974) | public int getSelectedIndex() {
      method getItems (line 1978) | public List<PaletteItemSnapshot> getItems() {
      method withSelectedIndex (line 1982) | PaletteSnapshot withSelectedIndex(int selectedIndex) {
      method copy (line 1986) | PaletteSnapshot copy() {
      method selectedValue (line 1990) | String selectedValue() {
    class PaletteItemSnapshot (line 1998) | public static final class PaletteItemSnapshot {
      method PaletteItemSnapshot (line 2005) | private PaletteItemSnapshot(String value, String display, String des...
      method getValue (line 2012) | public String getValue() {
      method getDisplay (line 2016) | public String getDisplay() {
      method getDescription (line 2020) | public String getDescription() {
      method getGroup (line 2024) | public String getGroup() {
    type SlashMenuAction (line 2029) | enum SlashMenuAction {
    type EnterAction (line 2035) | enum EnterAction {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/acp/AcpCodingCliAgentFactory.java
  class AcpCodingCliAgentFactory (line 14) | final class AcpCodingCliAgentFactory extends DefaultCodingCliAgentFactory {
    method AcpCodingCliAgentFactory (line 19) | AcpCodingCliAgentFactory(AcpToolApprovalDecorator.PermissionGateway pe...
    method prepareMcpRuntime (line 25) | @Override
    method createToolExecutorDecorator (line 39) | @Override

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/acp/AcpCommand.java
  class AcpCommand (line 13) | public class AcpCommand {
    method AcpCommand (line 20) | public AcpCommand(Map<String, String> env, Properties properties, Path...
    method run (line 26) | public int run(List<String> args, InputStream in, OutputStream out, Ou...
    method printHelp (line 44) | private void printHelp(OutputStream err) {
    method writeLine (line 57) | private void writeLine(OutputStream stream, String line) {
    method safeMessage (line 65) | private String safeMessage(Throwable throwable) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/acp/AcpJsonRpcServer.java
  class AcpJsonRpcServer (line 69) | public class AcpJsonRpcServer implements Closeable {
    type AgentFactoryProvider (line 71) | interface AgentFactoryProvider {
      method create (line 73) | CodingCliAgentFactory create(CodeCommandOptions options,
    method AcpJsonRpcServer (line 101) | public AcpJsonRpcServer(InputStream inputStream,
    method AcpJsonRpcServer (line 115) | AcpJsonRpcServer(InputStream inputStream,
    method run (line 127) | public int run() {
    method handleMessage (line 157) | private void handleMessage(final JSONObject message) {
    method handleRequest (line 183) | private void handleRequest(Object id, String method, JSONObject params) {
    method handleNotification (line 229) | private void handleNotification(String method, JSONObject params) {
    method buildInitializeResponse (line 241) | private Map<String, Object> buildInitializeResponse(JSONObject params) {
    method sendResponse (line 271) | private void sendResponse(Object id, Map<String, Object> result) {
    method sendError (line 279) | private void sendError(Object id, int code, String message) {
    method sendNotification (line 290) | private void sendNotification(String method, Map<String, Object> param...
    method sendRequest (line 298) | private void sendRequest(String id, String method, Map<String, Object>...
    method writeMessage (line 307) | private void writeMessage(Map<String, Object> payload) {
    method sendSessionUpdate (line 314) | private void sendSessionUpdate(String sessionId, Map<String, Object> u...
    method sendAvailableCommandsUpdate (line 321) | private void sendAvailableCommandsUpdate(String sessionId) {
    method requireSession (line 331) | private SessionHandle requireSession(String sessionId) {
    method logError (line 339) | private void logError(String message) {
    method createSession (line 346) | private SessionHandle createSession(JSONObject params, boolean loadExi...
    method promptSession (line 376) | private void promptSession(final Object requestId, JSONObject params) ...
    method setSessionMode (line 396) | private Map<String, Object> setSessionMode(JSONObject params) throws E...
    method setSessionConfigOption (line 404) | private Map<String, Object> setSessionConfigOption(JSONObject params) ...
    method cancelSession (line 418) | private void cancelSession(JSONObject params) {
    method listSessions (line 435) | private List<Map<String, Object>> listSessions(JSONObject params) thro...
    method requestPermission (line 451) | private AcpToolApprovalDecorator.PermissionDecision requestPermission(...
    method buildPermissionToolCall (line 478) | private Map<String, Object> buildPermissionToolCall(String toolName,
    method buildPermissionOptions (line 489) | private List<Map<String, Object>> buildPermissionOptions() {
    method buildCancelledPermissionResponse (line 498) | private JSONObject buildCancelledPermissionResponse() {
    method logMcpWarnings (line 508) | private void logMcpWarnings(CliMcpRuntimeManager runtimeManager) {
    method resolveMcpConfig (line 517) | private CliResolvedMcpConfig resolveMcpConfig(JSONArray mcpServers) {
    method resolveSessionOptions (line 553) | private CodeCommandOptions resolveSessionOptions(String workspace, Str...
    method createSessionManager (line 570) | private CodingSessionManager createSessionManager(CodeCommandOptions o...
    method flattenPrompt (line 585) | private String flattenPrompt(JSONArray blocks) {
    method appendBlock (line 608) | private void appendBlock(StringBuilder builder, String text) {
    method normalizeType (line 618) | private String normalizeType(String type) {
    method mapToolKind (line 622) | private String mapToolKind(String toolName) {
    method validateDefinition (line 633) | private String validateDefinition(CliMcpServerDefinition definition) {
    method normalizeTransportType (line 650) | private String normalizeTransportType(String type, String command) {
    method toStringList (line 659) | private List<String> toStringList(JSONArray values) {
    method toStringMap (line 673) | private Map<String, String> toStringMap(JSONObject object) {
    method newMap (line 687) | private Map<String, Object> newMap(Object... values) {
    method requestIdKey (line 701) | private String requestIdKey(Object id) {
    method requiredString (line 705) | private String requiredString(JSONObject params, String key) {
    method requiredArray (line 713) | private JSONArray requiredArray(JSONObject params, String key) {
    method requireAbsolutePath (line 721) | private String requireAbsolutePath(String path) {
    method trimToNull (line 733) | private String trimToNull(String value) {
    method isBlank (line 737) | private boolean isBlank(String value) {
    method firstNonBlank (line 741) | private String firstNonBlank(String... values) {
    method clip (line 753) | private String clip(String value, int maxChars) {
    method clipPreserveNewlines (line 764) | private String clipPreserveNewlines(String value, int maxChars) {
    method safeMessage (line 774) | private String safeMessage(Throwable throwable) {
    method textContent (line 790) | private Map<String, Object> textContent(String text) {
    method toolCallTextContent (line 797) | private List<Map<String, Object>> toolCallTextContent(String text) {
    method parseJsonOrText (line 807) | private Object parseJsonOrText(String value) {
    method toStructuredSessionUpdate (line 818) | private Map<String, Object> toStructuredSessionUpdate(SessionEvent eve...
    method payloadText (line 856) | private String payloadText(SessionEvent event, String key, String defa...
    method payloadValue (line 864) | private Object payloadValue(SessionEvent event, String key) {
    method buildTaskRawInput (line 871) | private Map<String, Object> buildTaskRawInput(SessionEvent event) {
    method buildTaskRawOutput (line 890) | private Map<String, Object> buildTaskRawOutput(SessionEvent event) {
    method buildTaskUpdateText (line 910) | private String buildTaskUpdateText(SessionEvent event) {
    method extractTaskPrimaryText (line 943) | private String extractTaskPrimaryText(SessionEvent event) {
    method isTeamTaskEvent (line 951) | private boolean isTeamTaskEvent(SessionEvent event) {
    method mapTaskStatusValue (line 969) | private String mapTaskStatusValue(String status) {
    method toTeamMessageAcpUpdate (line 987) | private Map<String, Object> toTeamMessageAcpUpdate(SessionEvent event) {
    method formatTeamMessageText (line 1024) | private String formatTeamMessageText(String messageType, String fromMe...
    method formatTeamMessageRoute (line 1043) | private String formatTeamMessageRoute(String fromMemberId, String toMe...
    method awaitPendingWork (line 1050) | private void awaitPendingWork() {
    method close (line 1065) | @Override
    class SessionHandle (line 1081) | private final class SessionHandle implements Closeable {
      method SessionHandle (line 1098) | private SessionHandle(CodeCommandOptions options,
      method getSession (line 1123) | private ManagedCodingSession getSession() {
      method buildSessionOpenResult (line 1127) | private Map<String, Object> buildSessionOpenResult() {
      method buildModes (line 1136) | private synchronized Map<String, Object> buildModes() {
      method buildConfigOptions (line 1154) | private synchronized List<Map<String, Object>> buildConfigOptions() {
      method setConfigOption (line 1177) | private synchronized List<Map<String, Object>> setConfigOption(Strin...
      method setMode (line 1190) | private synchronized void setMode(String modeId) throws Exception {
      method startPrompt (line 1194) | private void startPrompt(Runnable runnable) {
      method beginPrompt (line 1198) | private synchronized HeadlessCodingSessionRuntime.PromptControl begi...
      method runPrompt (line 1206) | private HeadlessCodingSessionRuntime.PromptResult runPrompt(String i...
      method runSlashCommand (line 1217) | private HeadlessCodingSessionRuntime.PromptResult runSlashCommand(St...
      method cancel (line 1249) | private void cancel() {
      method replayHistory (line 1256) | private void replayHistory() throws IOException {
      method sendAvailableCommandsUpdate (line 1269) | private void sendAvailableCommandsUpdate() {
      method appendSimpleEvent (line 1273) | private void appendSimpleEvent(SessionEventType type, String turnId,...
      method persistSessionIfConfigured (line 1289) | private void persistSessionIfConfigured() {
      method buildSlashCommandContext (line 1299) | private AcpSlashCommandSupport.Context buildSlashCommandContext() {
      method executeProvidersCommand (line 1330) | private synchronized String executeProvidersCommand() {
      method executeProviderCommand (line 1334) | private synchronized String executeProviderCommand(String argument) ...
      method executeModelCommand (line 1366) | private synchronized String executeModelCommand(String argument) thr...
      method executeExperimentalCommand (line 1375) | private synchronized String executeExperimentalCommand(String argume...
      method applyModeChange (line 1400) | private void applyModeChange(String rawModeId, boolean emitUpdates) ...
      method applyModelChange (line 1413) | private void applyModelChange(String rawValue,
      method switchToProviderProfile (line 1443) | private synchronized String switchToProviderProfile(String profileNa...
      method saveCurrentProviderProfile (line 1462) | private synchronized String saveCurrentProviderProfile(String profil...
      method addProviderProfile (line 1483) | private synchronized String addProviderProfile(String rawArguments) ...
      method editProviderProfile (line 1525) | private synchronized String editProviderProfile(String rawArguments)...
      method removeProviderProfile (line 1586) | private synchronized String removeProviderProfile(String profileName...
      method setDefaultProviderProfile (line 1607) | private synchronized String setDefaultProviderProfile(String profile...
      method renderProvidersOutput (line 1626) | private String renderProvidersOutput() {
      method renderCurrentProviderOutput (line 1656) | private String renderCurrentProviderOutput() {
      method renderModelOutput (line 1682) | private String renderModelOutput() {
      method renderExperimentalOutput (line 1703) | private String renderExperimentalOutput() {
      method renderExperimentalState (line 1719) | private String renderExperimentalState(Boolean configuredValue, bool...
      method normalizeExperimentalFeature (line 1724) | private String normalizeExperimentalFeature(String raw) {
      method parseExperimentalToggle (line 1742) | private Boolean parseExperimentalToggle(String raw) {
      method buildModeOptionValues (line 1756) | private List<Map<String, Object>> buildModeOptionValues() {
      method buildModelOptionValues (line 1771) | private List<Map<String, Object>> buildModelOptionValues() {
      method addProfileModelOptionValue (line 1798) | private void addProfileModelOptionValue(LinkedHashMap<String, Map<St...
      method addModelOptionValue (line 1815) | private void addModelOptionValue(LinkedHashMap<String, Map<String, O...
      method isSupportedModelValue (line 1832) | private boolean isSupportedModelValue(String value) {
      method currentApprovalMode (line 1852) | private ApprovalMode currentApprovalMode() {
      method approvalModeName (line 1856) | private String approvalModeName(ApprovalMode mode) {
      method approvalModeDescription (line 1866) | private String approvalModeDescription(ApprovalMode mode) {
      method emitModeUpdate (line 1876) | private void emitModeUpdate() {
      method emitConfigOptionUpdate (line 1888) | private void emitConfigOptionUpdate() {
      method resolveEffectiveProfileName (line 1899) | private String resolveEffectiveProfileName() {
      method resolveCurrentProviderOptions (line 1910) | private CodeCommandOptions resolveCurrentProviderOptions(String mode...
      method resolveProfileRuntimeOptions (line 1931) | private CodeCommandOptions resolveProfileRuntimeOptions(CliProviderP...
      method rebindSession (line 1961) | private void rebindSession(CodeCommandOptions nextOptions) throws Ex...
      method applySessionOptionsChange (line 2012) | private void applySessionOptionsChange(CodeCommandOptions nextOptions,
      method completePrompt (line 2042) | private void completePrompt(HeadlessCodingSessionRuntime.PromptContr...
      method rollbackDeferredSessionOptions (line 2063) | private void rollbackDeferredSessionOptions(CodeCommandOptions defer...
      method hasActivePrompt (line 2080) | private boolean hasActivePrompt() {
      method sameRuntimeConfig (line 2084) | private boolean sameRuntimeConfig(CodeCommandOptions left, CodeComma...
      method samePlatform (line 2099) | private boolean samePlatform(PlatformType left, PlatformType right) {
      method sameProtocol (line 2109) | private boolean sameProtocol(CliProtocol left, CliProtocol right) {
      method sameValue (line 2119) | private boolean sameValue(String left, String right) {
      method parseProviderProfileMutation (line 2123) | private ProviderProfileMutation parseProviderProfileMutation(String ...
      method requireProviderMutationValue (line 2197) | private String requireProviderMutationValue(String[] tokens, int ind...
      method parseProviderType (line 2204) | private PlatformType parseProviderType(String raw) {
      method parseProviderProtocol (line 2216) | private CliProtocol parseProviderProtocol(String raw) {
      method isSupportedProviderProtocol (line 2227) | private boolean isSupportedProviderProtocol(PlatformType provider, C...
      method normalizeStoredProtocol (line 2234) | private String normalizeStoredProtocol(String raw, PlatformType prov...
      method currentProtocol (line 2241) | private CliProtocol currentProtocol() {
      method maskSecret (line 2245) | private String maskSecret(String value) {
      method toHistoryUpdate (line 2256) | private Map<String, Object> toHistoryUpdate(SessionEvent event) {
      method payloadText (line 2334) | private String payloadText(SessionEvent event, String key, String de...
      method payloadJsonText (line 2342) | private Object payloadJsonText(SessionEvent event, String key) {
      method registerTaskEventBridge (line 2346) | private CodingTaskSessionEventBridge registerTaskEventBridge() {
      method mapTaskStatus (line 2366) | private String mapTaskStatus(String status) {
      method close (line 2387) | @Override
      class ProviderProfileMutation (line 2405) | private final class ProviderProfileMutation {
        method ProviderProfileMutation (line 2416) | private ProviderProfileMutation(String profileName) {
        method hasAnyFieldChanges (line 2420) | private boolean hasAnyFieldChanges() {
    class AcpTurnObserver (line 2433) | private final class AcpTurnObserver extends HeadlessTurnObserver.Adapt...
      method AcpTurnObserver (line 2437) | private AcpTurnObserver(String sessionId) {
      method onTurnStarted (line 2441) | @Override
      method onReasoningDelta (line 2449) | @Override
      method onAssistantDelta (line 2457) | @Override
      method onToolCall (line 2465) | @Override
      method onToolResult (line 2480) | @Override
      method onTurnError (line 2496) | @Override
      method onSessionEvent (line 2504) | @Override

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/acp/AcpSlashCommandSupport.java
  class AcpSlashCommandSupport (line 39) | final class AcpSlashCommandSupport {
    method AcpSlashCommandSupport (line 67) | private AcpSlashCommandSupport() {
    method availableCommands (line 70) | static List<Map<String, Object>> availableCommands() {
    method supports (line 86) | static boolean supports(String input) {
    method execute (line 90) | static ExecutionResult execute(Context context, String input) throws E...
    method executeRuntimeCommand (line 160) | private static String executeRuntimeCommand(Context context,
    method parse (line 181) | private static ParsedCommand parse(String input) {
    method findSpec (line 199) | private static CommandSpec findSpec(String name) {
    method renderHelp (line 211) | private static String renderHelp() {
    method renderStatus (line 224) | private static String renderStatus(Context context) {
    method renderSession (line 251) | private static String renderSession(Context context) {
    method renderSkills (line 281) | private static String renderSkills(Context context, String argument) {
    method renderAgents (line 321) | private static String renderAgents(Context context, String argument) {
    method renderMcp (line 363) | private static String renderMcp(Context context) {
    method renderSessions (line 392) | private static String renderSessions(Context context) throws Exception {
    method renderHistory (line 423) | private static String renderHistory(Context context, String targetSess...
    method renderTree (line 444) | private static String renderTree(Context context, String rootArgument)...
    method renderEvents (line 457) | private static String renderEvents(Context context, String limitArgume...
    method renderCompacts (line 481) | private static String renderCompacts(Context context, String limitArgu...
    method renderCheckpoint (line 499) | private static String renderCheckpoint(Context context) {
    method renderTeam (line 508) | private static String renderTeam(Context context, String argument) thr...
    method resolveWorkspaceRoot (line 538) | private static java.nio.file.Path resolveWorkspaceRoot(Context context) {
    method renderProcesses (line 549) | private static String renderProcesses(Context context) {
    method renderProcess (line 571) | private static String renderProcess(Context context, String rawArgumen...
    method snapshot (line 598) | private static CodingSessionSnapshot snapshot(ManagedCodingSession ses...
    method mergeCurrentSession (line 602) | private static List<CodingSessionDescriptor> mergeCurrentSession(List<...
    method resolveTargetDescriptor (line 617) | private static CodingSessionDescriptor resolveTargetDescriptor(List<Co...
    method resolveHistory (line 635) | private static List<CodingSessionDescriptor> resolveHistory(List<Codin...
    method renderTreeLines (line 656) | private static List<String> renderTreeLines(List<CodingSessionDescript...
    method renderTreeNode (line 714) | private static void renderTreeNode(List<String> lines,
    method renderTreeLabel (line 740) | private static String renderTreeLabel(CodingSessionDescriptor session,...
    method buildCompactLines (line 751) | private static List<String> buildCompactLines(List<SessionEvent> event...
    method renderProcessStatusOutput (line 790) | private static String renderProcessStatusOutput(BashProcessInfo proces...
    method renderProcessDetailsOutput (line 799) | private static String renderProcessDetailsOutput(BashProcessInfo proce...
    method appendProcessSummary (line 808) | private static void appendProcessSummary(StringBuilder builder, BashPr...
    method findSkill (line 824) | private static CodingSkillDescriptor findSkill(List<CodingSkillDescrip...
    method findAgent (line 837) | private static CodingAgentDefinition findAgent(List<CodingAgentDefinit...
    method renderAllowedTools (line 854) | private static String renderAllowedTools(CodingAgentDefinition definit...
    method renderMcpSummary (line 871) | private static String renderMcpSummary(CliMcpRuntimeManager runtimeMan...
    method resolveCompactMode (line 906) | private static String resolveCompactMode(SessionEvent event) {
    method formatCompactDelta (line 924) | private static String formatCompactDelta(Integer before, Integer after) {
    method parseLimit (line 928) | private static Integer parseLimit(String raw) {
    method defaultInt (line 941) | private static int defaultInt(Integer value) {
    method payloadInt (line 945) | private static Integer payloadInt(Map<String, Object> payload, String ...
    method payloadBoolean (line 960) | private static boolean payloadBoolean(Map<String, Object> payload, Str...
    method payloadString (line 971) | private static String payloadString(Map<String, Object> payload, Strin...
    method formatTimestamp (line 979) | private static String formatTimestamp(long epochMs) {
    method clip (line 988) | private static String clip(String value, int maxChars) {
    method firstNonBlank (line 999) | private static String firstNonBlank(String... values) {
    method trimToNull (line 1011) | private static String trimToNull(String value) {
    method isBlank (line 1019) | private static boolean isBlank(String value) {
    method splitWhitespace (line 1023) | private static List<String> splitWhitespace(String value) {
    class Context (line 1030) | static final class Context {
      method Context (line 1038) | Context(ManagedCodingSession session,
      method Context (line 1046) | Context(ManagedCodingSession session,
    type RuntimeCommandHandler (line 1061) | interface RuntimeCommandHandler {
      method executeProviders (line 1063) | String executeProviders() throws Exception;
      method executeProvider (line 1065) | String executeProvider(String argument) throws Exception;
      method executeModel (line 1067) | String executeModel(String argument) throws Exception;
      method executeExperimental (line 1069) | String executeExperimental(String argument) throws Exception;
    class ExecutionResult (line 1072) | static final class ExecutionResult {
      method ExecutionResult (line 1075) | private ExecutionResult(String output) {
      method of (line 1079) | static ExecutionResult of(String output) {
      method getOutput (line 1083) | String getOutput() {
    class CommandSpec (line 1088) | private static final class CommandSpec {
      method CommandSpec (line 1093) | private CommandSpec(String name, String description, String inputHin...
    class ParsedCommand (line 1100) | private static final class ParsedCommand {
      method ParsedCommand (line 1104) | private ParsedCommand(String name, String argument) {
    type RuntimeCommand (line 1110) | private enum RuntimeCommand {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/acp/AcpToolApprovalDecorator.java
  class AcpToolApprovalDecorator (line 15) | public class AcpToolApprovalDecorator implements ToolExecutorDecorator {
    type PermissionGateway (line 17) | public interface PermissionGateway {
      method requestApproval (line 19) | PermissionDecision requestApproval(String toolName,
    class PermissionDecision (line 24) | public static final class PermissionDecision {
      method PermissionDecision (line 29) | public PermissionDecision(boolean approved, String optionId) {
      method isApproved (line 34) | public boolean isApproved() {
      method getOptionId (line 38) | public String getOptionId() {
    method AcpToolApprovalDecorator (line 46) | public AcpToolApprovalDecorator(ApprovalMode approvalMode, PermissionG...
    method decorate (line 51) | @Override
    method requiresApproval (line 67) | private boolean requiresApproval(String toolName, AgentToolCall call) {
    method requestApproval (line 85) | private void requestApproval(String toolName, AgentToolCall call) thro...
    method buildRawInput (line 95) | private Map<String, Object> buildRawInput(String toolName, AgentToolCa...
    method buildApprovalRejectedMessage (line 103) | private String buildApprovalRejectedMessage(String toolName, AgentTool...
    method parseArguments (line 108) | private JSONObject parseArguments(String rawArguments) {
    method firstNonBlank (line 120) | private String firstNonBlank(String... values) {
    method isBlank (line 132) | private boolean isBlank(String value) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/agent/CliCodingAgentRegistry.java
  class CliCodingAgentRegistry (line 26) | public class CliCodingAgentRegistry {
    method CliCodingAgentRegistry (line 31) | public CliCodingAgentRegistry(Path workspaceRoot, List<String> configu...
    method loadRegistry (line 40) | public CodingAgentDefinitionRegistry loadRegistry() {
    method listDefinitions (line 44) | public List<CodingAgentDefinition> listDefinitions() {
    method listRoots (line 54) | public List<Path> listRoots() {
    method loadDirectory (line 74) | private void loadDirectory(Path directory, List<CodingAgentDefinition>...
    method loadDefinition (line 92) | private CodingAgentDefinition loadDefinition(Path file) {
    method parse (line 136) | private ParsedDefinition parse(String raw) {
    method parseAllowedTools (line 172) | private Set<String> parseAllowedTools(String raw) {
    method parseEnum (line 202) | private <E extends Enum<E>> E parseEnum(String raw, Class<E> type, E d...
    method parseBoolean (line 215) | private boolean parseBoolean(String raw, boolean defaultValue) {
    method mergeDefinition (line 229) | private void mergeDefinition(List<CodingAgentDefinition> ordered, Codi...
    method sameKey (line 251) | private boolean sameKey(String left, String right) {
    method workspaceAgentsDirectory (line 256) | private Path workspaceAgentsDirectory() {
    method homeAgentsDirectory (line 260) | private Path homeAgentsDirectory() {
    method hasSupportedExtension (line 267) | private boolean hasSupportedExtension(Path file) {
    method defaultName (line 275) | private String defaultName(Path file) {
    method defaultToolName (line 284) | private String defaultToolName(String name) {
    method normalizeToolSegment (line 292) | private String normalizeToolSegment(String value) {
    method normalizeKey (line 323) | private String normalizeKey(String value) {
    method normalizeToken (line 331) | private String normalizeToken(String value) {
    method stripQuotes (line 338) | private String stripQuotes(String value) {
    method firstNonBlank (line 349) | private String firstNonBlank(String... values) {
    method trimToNull (line 362) | private String trimToNull(String value) {
    method isBlank (line 370) | private boolean isBlank(String value) {
    class ParsedDefinition (line 374) | private static final class ParsedDefinition {
      method ParsedDefinition (line 378) | private ParsedDefinition(List<MetadataEntry> metadata, String body) {
      method meta (line 383) | private String meta(String key) {
    class MetadataEntry (line 397) | private static final class MetadataEntry {
      method MetadataEntry (line 401) | private MetadataEntry(String key, String value) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/command/CodeCommand.java
  class CodeCommand (line 34) | public class CodeCommand {
    type InteractiveBackend (line 36) | private enum InteractiveBackend {
    method CodeCommand (line 48) | public CodeCommand(CodingCliAgentFactory agentFactory,
    method CodeCommand (line 55) | public CodeCommand(CodingCliAgentFactory agentFactory,
    method run (line 67) | public int run(List<String> args, TerminalIO terminal) {
    method printHelp (line 149) | private void printHelp(TerminalIO terminal) {
    method printMcpStartupWarnings (line 246) | private void printMcpStartupWarnings(TerminalIO terminal, CliMcpRuntim...
    method safeMessage (line 260) | private String safeMessage(Throwable throwable) {
    method safeMessage (line 265) | private String safeMessage(String value) {
    method stackTraceOf (line 269) | private String stackTraceOf(Throwable throwable) {
    method createSessionManager (line 277) | private CodingSessionManager createSessionManager(CodeCommandOptions o...
    method resolveInteractiveBackend (line 292) | private InteractiveBackend resolveInteractiveBackend(CodeCommandOption...
    method closeQuietly (line 316) | private void closeQuietly(TerminalIO terminal) {
    method firstNonBlank (line 326) | private String firstNonBlank(String... values) {
    method isBlank (line 338) | private boolean isBlank(String value) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/command/CodeCommandOptions.java
  class CodeCommandOptions (line 8) | public final class CodeCommandOptions {
    method CodeCommandOptions (line 54) | public CodeCommandOptions(boolean help,
    method CodeCommandOptions (line 108) | public CodeCommandOptions(boolean help,
    method CodeCommandOptions (line 172) | public CodeCommandOptions(boolean help,
    method CodeCommandOptions (line 239) | private CodeCommandOptions(boolean help,
    method isHelp (line 307) | public boolean isHelp() {
    method getUiMode (line 311) | public CliUiMode getUiMode() {
    method getProvider (line 315) | public PlatformType getProvider() {
    method getProtocol (line 319) | public CliProtocol getProtocol() {
    method getModel (line 323) | public String getModel() {
    method getApiKey (line 327) | public String getApiKey() {
    method getBaseUrl (line 331) | public String getBaseUrl() {
    method getWorkspace (line 335) | public String getWorkspace() {
    method getWorkspaceDescription (line 339) | public String getWorkspaceDescription() {
    method getSystemPrompt (line 343) | public String getSystemPrompt() {
    method getInstructions (line 347) | public String getInstructions() {
    method getPrompt (line 351) | public String getPrompt() {
    method getMaxSteps (line 355) | public int getMaxSteps() {
    method getTemperature (line 359) | public Double getTemperature() {
    method getTopP (line 363) | public Double getTopP() {
    method getMaxOutputTokens (line 367) | public Integer getMaxOutputTokens() {
    method getParallelToolCalls (line 371) | public Boolean getParallelToolCalls() {
    method isAllowOutsideWorkspace (line 375) | public boolean isAllowOutsideWorkspace() {
    method getSessionId (line 379) | public String getSessionId() {
    method getResumeSessionId (line 383) | public String getResumeSessionId() {
    method getForkSessionId (line 387) | public String getForkSessionId() {
    method getSessionStoreDir (line 391) | public String getSessionStoreDir() {
    method getTheme (line 395) | public String getTheme() {
    method getApprovalMode (line 399) | public ApprovalMode getApprovalMode() {
    method isNoSession (line 403) | public boolean isNoSession() {
    method isAutoSaveSession (line 407) | public boolean isAutoSaveSession() {
    method isAutoCompact (line 411) | public boolean isAutoCompact() {
    method getCompactContextWindowTokens (line 415) | public int getCompactContextWindowTokens() {
    method getCompactReserveTokens (line 419) | public int getCompactReserveTokens() {
    method getCompactKeepRecentTokens (line 423) | public int getCompactKeepRecentTokens() {
    method getCompactSummaryMaxOutputTokens (line 427) | public int getCompactSummaryMaxOutputTokens() {
    method isStream (line 431) | public boolean isStream() {
    method isVerbose (line 435) | public boolean isVerbose() {
    method withRuntime (line 439) | public CodeCommandOptions withRuntime(PlatformType provider,
    method withStream (line 459) | public CodeCommandOptions withStream(boolean stream) {
    method withApprovalMode (line 475) | public CodeCommandOptions withApprovalMode(ApprovalMode approvalMode) {
    method withSessionContext (line 491) | public CodeCommandOptions withSessionContext(String workspace,
    method copy (line 510) | private CodeCommandOptions copy(PlatformType provider,

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/command/CodeCommandOptionsParser.java
  class CodeCommandOptionsParser (line 18) | public class CodeCommandOptionsParser {
    method parse (line 20) | public CodeCommandOptions parse(List<String> args,
    method resolveUiMode (line 343) | private CliUiMode resolveUiMode(Map<String, String> values,
    method envValue (line 355) | private String envValue(Map<String, String> env, String name) {
    method propertyValue (line 359) | private String propertyValue(Properties properties, String name) {
    method normalizeOptionName (line 363) | private String normalizeOptionName(String option) {
    method parseInteger (line 370) | private int parseInteger(String value, String name) {
    method parseIntegerOrNull (line 378) | private Integer parseIntegerOrNull(String value, String name) {
    method parseDoubleOrNull (line 385) | private Double parseDoubleOrNull(String value, String name) {
    method parseBooleanOrDefault (line 396) | private Boolean parseBooleanOrDefault(String value, boolean defaultVal...
    method parseBoolean (line 403) | private boolean parseBoolean(String value) {
    method firstNonBlank (line 413) | private String firstNonBlank(String... values) {
    method isBlank (line 425) | private boolean isBlank(String value) {
    method trimToNull (line 429) | private String trimToNull(String value) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/command/CustomCommandRegistry.java
  class CustomCommandRegistry (line 15) | public class CustomCommandRegistry {
    method CustomCommandRegistry (line 19) | public CustomCommandRegistry(Path workspaceRoot) {
    method list (line 23) | public List<CustomCommandTemplate> list() {
    method find (line 32) | public CustomCommandTemplate find(String name) {
    method loadDirectory (line 44) | private void loadDirectory(Path directory, Map<String, CustomCommandTe...
    method loadTemplate (line 62) | private CustomCommandTemplate loadTemplate(Path file) {
    method workspaceCommandsDirectory (line 87) | private Path workspaceCommandsDirectory() {
    method homeCommandsDirectory (line 91) | private Path homeCommandsDirectory() {
    method hasSupportedExtension (line 99) | private boolean hasSupportedExtension(Path file) {
    method isBlank (line 107) | private boolean isBlank(String value) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/command/CustomCommandTemplate.java
  class CustomCommandTemplate (line 5) | public class CustomCommandTemplate {
    method CustomCommandTemplate (line 12) | public CustomCommandTemplate(String name, String description, String t...
    method getName (line 19) | public String getName() {
    method getDescription (line 23) | public String getDescription() {
    method getTemplate (line 27) | public String getTemplate() {
    method getSource (line 31) | public String getSource() {
    method render (line 35) | public String render(Map<String, String> variables) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/config/CliWorkspaceConfig.java
  class CliWorkspaceConfig (line 6) | public class CliWorkspaceConfig {
    method CliWorkspaceConfig (line 16) | public CliWorkspaceConfig() {
    method CliWorkspaceConfig (line 19) | public CliWorkspaceConfig(String activeProfile,
    method builder (line 35) | public static Builder builder() {
    method toBuilder (line 39) | public Builder toBuilder() {
    method getActiveProfile (line 50) | public String getActiveProfile() {
    method setActiveProfile (line 54) | public void setActiveProfile(String activeProfile) {
    method getModelOverride (line 58) | public String getModelOverride() {
    method setModelOverride (line 62) | public void setModelOverride(String modelOverride) {
    method getExperimentalSubagentsEnabled (line 66) | public Boolean getExperimentalSubagentsEnabled() {
    method setExperimentalSubagentsEnabled (line 70) | public void setExperimentalSubagentsEnabled(Boolean experimentalSubage...
    method getExperimentalAgentTeamsEnabled (line 74) | public Boolean getExperimentalAgentTeamsEnabled() {
    method setExperimentalAgentTeamsEnabled (line 78) | public void setExperimentalAgentTeamsEnabled(Boolean experimentalAgent...
    method getEnabledMcpServers (line 82) | public List<String> getEnabledMcpServers() {
    method setEnabledMcpServers (line 86) | public void setEnabledMcpServers(List<String> enabledMcpServers) {
    method getSkillDirectories (line 90) | public List<String> getSkillDirectories() {
    method setSkillDirectories (line 94) | public void setSkillDirectories(List<String> skillDirectories) {
    method getAgentDirectories (line 98) | public List<String> getAgentDirectories() {
    method setAgentDirectories (line 102) | public void setAgentDirectories(List<String> agentDirectories) {
    method copy (line 106) | private List<String> copy(List<String> values) {
    class Builder (line 110) | public static final class Builder {
      method Builder (line 120) | private Builder() {
      method activeProfile (line 123) | public Builder activeProfile(String activeProfile) {
      method modelOverride (line 128) | public Builder modelOverride(String modelOverride) {
      method experimentalSubagentsEnabled (line 133) | public Builder experimentalSubagentsEnabled(Boolean experimentalSuba...
      method experimentalAgentTeamsEnabled (line 138) | public Builder experimentalAgentTeamsEnabled(Boolean experimentalAge...
      method enabledMcpServers (line 143) | public Builder enabledMcpServers(List<String> enabledMcpServers) {
      method skillDirectories (line 148) | public Builder skillDirectories(List<String> skillDirectories) {
      method agentDirectories (line 153) | public Builder agentDirectories(List<String> agentDirectories) {
      method build (line 158) | public CliWorkspaceConfig build() {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/factory/CodingCliAgentFactory.java
  type CodingCliAgentFactory (line 13) | public interface CodingCliAgentFactory {
    method prepare (line 15) | PreparedCodingAgent prepare(CodeCommandOptions options) throws Exception;
    method prepare (line 17) | default PreparedCodingAgent prepare(CodeCommandOptions options, Termin...
    method prepare (line 21) | default PreparedCodingAgent prepare(CodeCommandOptions options,
    method prepare (line 27) | default PreparedCodingAgent prepare(CodeCommandOptions options,
    class PreparedCodingAgent (line 34) | final class PreparedCodingAgent {
      method PreparedCodingAgent (line 40) | public PreparedCodingAgent(CodingAgent agent, CliProtocol protocol) {
      method PreparedCodingAgent (line 44) | public PreparedCodingAgent(CodingAgent agent,
      method getAgent (line 52) | public CodingAgent getAgent() {
      method getProtocol (line 56) | public CliProtocol getProtocol() {
      method getMcpRuntimeManager (line 60) | public CliMcpRuntimeManager getMcpRuntimeManager() {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/factory/CodingCliTuiFactory.java
  type CodingCliTuiFactory (line 9) | public interface CodingCliTuiFactory {
    method create (line 11) | CodingCliTuiSupport create(CodeCommandOptions options,

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/factory/DefaultCodingCliAgentFactory.java
  class DefaultCodingCliAgentFactory (line 69) | public class DefaultCodingCliAgentFactory implements CodingCliAgentFacto...
    method prepare (line 78) | @Override
    method prepare (line 83) | @Override
    method prepare (line 88) | @Override
    method prepare (line 95) | @Override
    method resolveProtocol (line 107) | CliProtocol resolveProtocol(CodeCommandOptions options) {
    method createModelClient (line 118) | protected AgentModelClient createModelClient(CodeCommandOptions option...
    method createConfiguration (line 136) | private Configuration createConfiguration(CodeCommandOptions options) {
    method prepareMcpRuntime (line 143) | protected CliMcpRuntimeManager prepareMcpRuntime(CodeCommandOptions op...
    method buildAgent (line 162) | private CodingAgent buildAgent(CodeCommandOptions options,
    method createToolExecutorDecorator (line 194) | protected ToolExecutorDecorator createToolExecutorDecorator(CodeComman...
    method buildWorkspaceContext (line 200) | WorkspaceContext buildWorkspaceContext(CodeCommandOptions options) {
    method buildWorkspaceContext (line 205) | WorkspaceContext buildWorkspaceContext(CodeCommandOptions options, Cli...
    method loadWorkspaceConfig (line 215) | private CliWorkspaceConfig loadWorkspaceConfig(String workspace) {
    method loadDefinitionRegistry (line 219) | CodingAgentDefinitionRegistry loadDefinitionRegistry(CodeCommandOption...
    method loadDefinitionRegistry (line 224) | CodingAgentDefinitionRegistry loadDefinitionRegistry(CodeCommandOption...
    method buildCodingOptions (line 240) | private CodingAgentOptions buildCodingOptions(CodeCommandOptions options,
    method buildAgentOptions (line 253) | private AgentOptions buildAgentOptions(CodeCommandOptions options) {
    method buildStreamExecutionOptions (line 261) | private StreamExecutionOptions buildStreamExecutionOptions() {
    method attachMcpRuntime (line 269) | private void attachMcpRuntime(io.github.lnyocly.ai4j.coding.CodingAgen...
    method attachExperimentalAgents (line 280) | private void attachExperimentalAgents(io.github.lnyocly.ai4j.coding.Co...
    method buildBackgroundWorkerSubAgent (line 298) | private SubAgentDefinition buildBackgroundWorkerSubAgent(CodeCommandOp...
    method buildDeliveryTeamSubAgent (line 321) | private SubAgentDefinition buildDeliveryTeamSubAgent(CodeCommandOption...
    method resolveExperimentalTeamStorageDirectory (line 439) | private Path resolveExperimentalTeamStorageDirectory(WorkspaceContext ...
    method teamMember (line 446) | private AgentTeamMember teamMember(String id,
    method buildExperimentalCodingAgent (line 470) | private Agent buildExperimentalCodingAgent(AgentModelClient modelClient,
    method renderDeliveryTeamSummary (line 493) | private String renderDeliveryTeamSummary(String objective, List<AgentT...
    method appendTeamMemberSummary (line 519) | private void appendTeamMemberSummary(StringBuilder builder, String nam...
    method isExperimentalSubagentsEnabled (line 527) | public static boolean isExperimentalSubagentsEnabled(CliWorkspaceConfi...
    method isExperimentalAgentTeamsEnabled (line 532) | public static boolean isExperimentalAgentTeamsEnabled(CliWorkspaceConf...
    method createHttpClient (line 537) | private OkHttpClient createHttpClient(boolean verbose) {
    method applyProviderConfig (line 551) | private void applyProviderConfig(Configuration configuration,
    method assertSupportedProtocol (line 627) | private void assertSupportedProtocol(PlatformType provider, CliProtoco...
    method defaultIfBlank (line 637) | private String defaultIfBlank(String value, String defaultValue) {
    method safeText (line 641) | private String safeText(String value) {
    method normalizeZhipuBaseUrl (line 645) | String normalizeZhipuBaseUrl(String baseUrl) {
    method normalizeRuntimeBaseUrl (line 659) | private String normalizeRuntimeBaseUrl(CodeCommandOptions options) {
    method stripSuffixIgnoreCase (line 669) | private String stripSuffixIgnoreCase(String value, String suffix) {
    method isBlank (line 681) | private boolean isBlank(String value) {
    method safeMessage (line 685) | private String safeMessage(Throwable throwable) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/factory/DefaultCodingCliTuiFactory.java
  class DefaultCodingCliTuiFactory (line 16) | public class DefaultCodingCliTuiFactory implements CodingCliTuiFactory {
    method create (line 18) | @Override

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/mcp/CliMcpConfig.java
  class CliMcpConfig (line 6) | public class CliMcpConfig {
    method CliMcpConfig (line 10) | public CliMcpConfig() {
    method CliMcpConfig (line 13) | public CliMcpConfig(Map<String, CliMcpServerDefinition> mcpServers) {
    method builder (line 19) | public static Builder builder() {
    method toBuilder (line 23) | public Builder toBuilder() {
    method getMcpServers (line 27) | public Map<String, CliMcpServerDefinition> getMcpServers() {
    method setMcpServers (line 31) | public void setMcpServers(Map<String, CliMcpServerDefinition> mcpServe...
    class Builder (line 37) | public static final class Builder {
      method Builder (line 41) | private Builder() {
      method mcpServers (line 44) | public Builder mcpServers(Map<String, CliMcpServerDefinition> mcpSer...
      method build (line 51) | public CliMcpConfig build() {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/mcp/CliMcpConfigManager.java
  class CliMcpConfigManager (line 22) | public class CliMcpConfigManager {
    method CliMcpConfigManager (line 26) | public CliMcpConfigManager(Path workspaceRoot) {
    method loadGlobalConfig (line 32) | public CliMcpConfig loadGlobalConfig() {
    method saveGlobalConfig (line 44) | public CliMcpConfig saveGlobalConfig(CliMcpConfig config) throws IOExc...
    method loadWorkspaceConfig (line 56) | public CliWorkspaceConfig loadWorkspaceConfig() {
    method saveWorkspaceConfig (line 65) | public CliWorkspaceConfig saveWorkspaceConfig(CliWorkspaceConfig confi...
    method resolve (line 74) | public CliResolvedMcpConfig resolve(Collection<String> pausedServerNam...
    method globalMcpPath (line 131) | public Path globalMcpPath() {
    method workspaceConfigPath (line 136) | public Path workspaceConfigPath() {
    method loadConfig (line 140) | private <T> T loadConfig(Path path, Class<T> type) {
    method persistNormalizedGlobalConfig (line 151) | private void persistNormalizedGlobalConfig(CliMcpConfig config) {
    method normalize (line 163) | private boolean normalize(CliMcpConfig config) {
    method normalize (line 196) | private void normalize(CliWorkspaceConfig config) {
    method normalize (line 207) | private CliMcpServerDefinition normalize(CliMcpServerDefinition defini...
    method validate (line 220) | private String validate(CliMcpServerDefinition definition) {
    method normalizeTransportType (line 237) | private String normalizeTransportType(String rawType, String command) {
    method toOrderedSet (line 249) | private Set<String> toOrderedSet(Collection<String> values) {
    method normalizeNames (line 263) | private List<String> normalizeNames(List<String> values) {
    method normalizeMap (line 277) | private Map<String, String> normalizeMap(Map<String, String> values) {
    method normalizeName (line 292) | private String normalizeName(String value) {
    method normalizeValue (line 296) | private String normalizeValue(String value) {
    method isBlank (line 300) | private boolean isBlank(String value) {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/mcp/CliMcpConnectionHandle.java
  class CliMcpConnectionHandle (line 9) | public final class CliMcpConnectionHandle {
    method CliMcpConnectionHandle (line 17) | CliMcpConnectionHandle(CliResolvedMcpServer server) {
    method getServerName (line 21) | String getServerName() {
    method getTransportType (line 25) | String getTransportType() {
    method getServer (line 29) | CliResolvedMcpServer getServer() {
    method getClientSession (line 33) | CliMcpRuntimeManager.ClientSession getClientSession() {
    method setClientSession (line 37) | void setClientSession(CliMcpRuntimeManager.ClientSession clientSession) {
    method getState (line 41) | String getState() {
    method setState (line 45) | void setState(String state) {
    method getErrorSummary (line 49) | String getErrorSummary() {
    method setErrorSummary (line 53) | void setErrorSummary(String errorSummary) {
    method getTools (line 57) | List<Tool> getTools() {
    method setTools (line 61) | void setTools(List<Tool> tools) {
    method toStatusSnapshot (line 69) | CliMcpStatusSnapshot toStatusSnapshot() {
    method closeQuietly (line 81) | void closeQuietly() {

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/mcp/CliMcpRuntimeManager.java
  class CliMcpRuntimeManager (line 28) | public final class CliMcpRuntimeManager implements AutoCloseable {
    method initialize (line 51) | public static CliMcpRuntimeManager initialize(Path workspaceRoot, Coll...
    method initialize (line 56) | public static CliMcpRuntimeManager initialize(CliResolvedMcpConfig res...
    method CliMcpRuntimeManager (line 65) | CliMcpRuntimeManager(CliResolvedMcpConfig resolvedConfig) {
    method CliMcpRuntimeManager (line 69) | CliMcpRuntimeManager(CliResolvedMcpConfig resolvedConfig, ClientFactor...
    method start (line 76) | public void start() {
    method getToolRegistry (line 138) | public AgentToolRegistry getToolRegistry() {
    method getToolExecutor (line 142) | public ToolExecutor getToolExecutor() {
    method getStatuses (line 146) | public List<CliMcpStatusSnapshot> getStatuses() {
    method buildStartupWarnings (line 150) | public List<String> buildStartupWarnings() {
    method hasStatuses (line 173) | public boolean hasStatuses() {
    method findServerNameByToolName (line 177) | public String findServerNameByToolName(String toolName) {
    method close (line 185) | @Override
    method rebuildToolView (line 201) | private void rebuildToolView() {
    method validateToolNames (line 231) | private void validateToolNames(CliResolvedMcpServer server,
    method convertTools (line 257) | private List<Tool> convertTools(List<McpToolDefinition> toolDefinition...
    method convertInputSchema (line 278) | private Tool.Function.Parameter convertInputSchema(Map<String, Object>...
    method convertProperty (line 310) | private Tool.Function.Property convertProperty(Map<String, Object> raw...
    method parseArguments (line 331) | private Object parseArguments(String rawArguments) {
    method normalizeToolName (line 342) | private String normalizeToolName(String value) {
    method asString (line 346) | private String asString(Object value) {
    method safeMessage (line 350) | private String safeMessage(Throwable throwable) {
    method firstNonBlank (line 366) | private String firstNonBlank(String... values) {
    method hasRelevantConfiguration (line 378) | private static boolean hasRelevantConfiguration(CliResolvedMcpConfig r...
    method isBlank (line 388) | private static boolean isBlank(String value) {
    type ClientFactory (line 392) | interface ClientFactory {
      method create (line 394) | ClientSession create(CliResolvedMcpServer server) throws Exception;
    type ClientSession (line 397) | interface ClientSession extends AutoCloseable {
      method connect (line 399) | void connect() throws Exception;
      method listTools (line 401) | List<McpToolDefinition> listTools() throws Exception;
      method callTool (line 403) | String callTool(String toolName, Object arguments) throws Exception;
      method close (line 405) | @Override
    class DefaultClientFactory (line 409) | private static final class DefaultClientFactory implements ClientFacto...
      method create (line 411) | @Override
    class McpClientSessionAdapter (line 432) | private static final class McpClientSessionAdapter implements ClientSe...
      method McpClientSessionAdapter (line 436) | private McpClientSessionAdapter(McpClient delegate) {
      method connect (line 440) | @Override
      method listTools (line 445) | @Override
      method callTool (line 450) | @Override
      method close (line 455) | @Override

FILE: ai4j-cli/src/main/java/io/github/lnyocly/ai4j/cli/mcp/CliMcpServerDefinition.java
  class CliMcpServerDefinition (line 8) | public class CliMcpServerDefinition {
    method CliMcpServerDefinition (line 18) | public CliMcpServerDefinition() {
    method CliMcpServerDefinition (line 21) | public CliMcpServerDefinition(String type,
    method builder (line 37) | public static Builder builder() {
    method toBuilder (line 41) | public Builder toBuilder() {
    method getType (line 52) | public String getType() {
    method setType (line 56) | public void setType(String type) {
    method getUrl (line 60) | public String getUrl() {
    method setUrl (line 64) | public void setUrl(String url) {
    method getCommand (line 68) | public String getCommand() {
    method setCommand (line 72) | public void setCommand(String command) {
    method getArgs (line 76) | public List<String> getArgs() {
    method setArgs (line 80) | public void setArgs(List<String> args) {
    method getEnv (line 84) | public Map<String, String> getEnv() {
    method setEnv (line 88) | public void setEnv(Map<St
Condensed preview — 1275 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (6,159K chars).
[
  {
    "path": ".editorconfig",
    "chars": 155,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 4\n\n[*.m"
  },
  {
    "path": ".github/workflows/docs-build.yml",
    "chars": 698,
    "preview": "name: docs-build\n\non:\n  pull_request:\n    paths:\n      - 'docs-site/**'\n      - '.github/workflows/docs-build.yml'\n  pus"
  },
  {
    "path": ".github/workflows/docs-pages.yml",
    "chars": 1243,
    "preview": "name: docs-pages\n\non:\n  push:\n    branches: [main]\n    paths:\n      - 'docs-site/**'\n      - '.github/workflows/docs-pag"
  },
  {
    "path": ".gitignore",
    "chars": 931,
    "preview": "target/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### IntelliJ IDEA ###\n.idea/mod"
  },
  {
    "path": "LICENSE",
    "chars": 11356,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README-EN.md",
    "chars": 21622,
    "preview": "<p align=\"center\">\n  <img src=\"https://capsule-render.vercel.app/api?type=waving&color=0:6A5ACD,100:2E86C1&height=180&se"
  },
  {
    "path": "README.md",
    "chars": 27558,
    "preview": "<p align=\"center\">\n  <img src=\"https://capsule-render.vercel.app/api?type=waving&color=0:6A5ACD,100:2E86C1&height=180&se"
  },
  {
    "path": "ai4j/pom.xml",
    "chars": 13689,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/AgentFlow.java",
    "chars": 2306,
    "preview": "package io.github.lnyocly.ai4j.agentflow;\n\nimport io.github.lnyocly.ai4j.agentflow.chat.AgentFlowChatService;\nimport io."
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/AgentFlowConfig.java",
    "chars": 1129,
    "preview": "package io.github.lnyocly.ai4j.agentflow;\n\nimport io.github.lnyocly.ai4j.agentflow.trace.AgentFlowTraceListener;\nimport "
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/AgentFlowException.java",
    "chars": 286,
    "preview": "package io.github.lnyocly.ai4j.agentflow;\n\npublic class AgentFlowException extends RuntimeException {\n\n    public AgentF"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/AgentFlowType.java",
    "chars": 101,
    "preview": "package io.github.lnyocly.ai4j.agentflow;\n\npublic enum AgentFlowType {\n    DIFY,\n    COZE,\n    N8N\n}\n"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/AgentFlowUsage.java",
    "chars": 473,
    "preview": "package io.github.lnyocly.ai4j.agentflow;\n\nimport lombok.AccessLevel;\nimport lombok.AllArgsConstructor;\nimport lombok.Bu"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/AgentFlowChatEvent.java",
    "chars": 652,
    "preview": "package io.github.lnyocly.ai4j.agentflow.chat;\n\nimport io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;\nimport lombok.Ac"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/AgentFlowChatListener.java",
    "chars": 295,
    "preview": "package io.github.lnyocly.ai4j.agentflow.chat;\n\npublic interface AgentFlowChatListener {\n\n    void onEvent(AgentFlowChat"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/AgentFlowChatRequest.java",
    "chars": 803,
    "preview": "package io.github.lnyocly.ai4j.agentflow.chat;\n\nimport lombok.AccessLevel;\nimport lombok.AllArgsConstructor;\nimport lomb"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/AgentFlowChatResponse.java",
    "chars": 597,
    "preview": "package io.github.lnyocly.ai4j.agentflow.chat;\n\nimport io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;\nimport lombok.Ac"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/AgentFlowChatService.java",
    "chars": 271,
    "preview": "package io.github.lnyocly.ai4j.agentflow.chat;\n\npublic interface AgentFlowChatService {\n\n    AgentFlowChatResponse chat("
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/CozeAgentFlowChatService.java",
    "chars": 17803,
    "preview": "package io.github.lnyocly.ai4j.agentflow.chat;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONArra"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/chat/DifyAgentFlowChatService.java",
    "chars": 11386,
    "preview": "package io.github.lnyocly.ai4j.agentflow.chat;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONObje"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/support/AgentFlowSupport.java",
    "chars": 15174,
    "preview": "package io.github.lnyocly.ai4j.agentflow.support;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONO"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/trace/AgentFlowTraceContext.java",
    "chars": 831,
    "preview": "package io.github.lnyocly.ai4j.agentflow.trace;\n\nimport io.github.lnyocly.ai4j.agentflow.AgentFlowType;\nimport lombok.Ac"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/trace/AgentFlowTraceListener.java",
    "chars": 408,
    "preview": "package io.github.lnyocly.ai4j.agentflow.trace;\n\npublic interface AgentFlowTraceListener {\n\n    default void onStart(Age"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/AgentFlowWorkflowEvent.java",
    "chars": 795,
    "preview": "package io.github.lnyocly.ai4j.agentflow.workflow;\n\nimport io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;\nimport lombo"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/AgentFlowWorkflowListener.java",
    "chars": 311,
    "preview": "package io.github.lnyocly.ai4j.agentflow.workflow;\n\npublic interface AgentFlowWorkflowListener {\n\n    void onEvent(Agent"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/AgentFlowWorkflowRequest.java",
    "chars": 743,
    "preview": "package io.github.lnyocly.ai4j.agentflow.workflow;\n\nimport lombok.AccessLevel;\nimport lombok.AllArgsConstructor;\nimport "
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/AgentFlowWorkflowResponse.java",
    "chars": 745,
    "preview": "package io.github.lnyocly.ai4j.agentflow.workflow;\n\nimport io.github.lnyocly.ai4j.agentflow.AgentFlowUsage;\nimport lombo"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/AgentFlowWorkflowService.java",
    "chars": 293,
    "preview": "package io.github.lnyocly.ai4j.agentflow.workflow;\n\npublic interface AgentFlowWorkflowService {\n\n    AgentFlowWorkflowRe"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/CozeAgentFlowWorkflowService.java",
    "chars": 10691,
    "preview": "package io.github.lnyocly.ai4j.agentflow.workflow;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSON"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/DifyAgentFlowWorkflowService.java",
    "chars": 12273,
    "preview": "package io.github.lnyocly.ai4j.agentflow.workflow;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSON"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/agentflow/workflow/N8nAgentFlowWorkflowService.java",
    "chars": 2560,
    "preview": "package io.github.lnyocly.ai4j.agentflow.workflow;\n\nimport io.github.lnyocly.ai4j.agentflow.AgentFlowConfig;\nimport io.g"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/annotation/FunctionCall.java",
    "chars": 417,
    "preview": "package io.github.lnyocly.ai4j.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retenti"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/annotation/FunctionParameter.java",
    "chars": 440,
    "preview": "package io.github.lnyocly.ai4j.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retenti"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/annotation/FunctionRequest.java",
    "chars": 411,
    "preview": "package io.github.lnyocly.ai4j.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retenti"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/auth/BearerTokenUtils.java",
    "chars": 5214,
    "preview": "package io.github.lnyocly.ai4j.auth;\n\nimport com.auth0.jwt.JWT;\nimport com.auth0.jwt.algorithms.Algorithm;\nimport com.go"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/AiPlatform.java",
    "chars": 471,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.Data;\n\n@Data\npublic class AiPlatform {\n    private String id;\n    "
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/BaichuanConfig.java",
    "chars": 361,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/DashScopeConfig.java",
    "chars": 472,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/DeepSeekConfig.java",
    "chars": 434,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/DoubaoConfig.java",
    "chars": 695,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/HunyuanConfig.java",
    "chars": 457,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/JinaConfig.java",
    "chars": 333,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/LingyiConfig.java",
    "chars": 429,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/McpConfig.java",
    "chars": 1849,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.Data;\n\n/**\n * @Author cly\n * @Description MCP (Model Context Proto"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/MilvusConfig.java",
    "chars": 1043,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/MinimaxConfig.java",
    "chars": 457,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/MoonshotConfig.java",
    "chars": 428,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/OkHttpConfig.java",
    "chars": 591,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/OllamaConfig.java",
    "chars": 510,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/OpenAiConfig.java",
    "chars": 826,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/PgVectorConfig.java",
    "chars": 710,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/PineconeConfig.java",
    "chars": 509,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/QdrantConfig.java",
    "chars": 540,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/config/ZhipuConfig.java",
    "chars": 489,
    "preview": "package io.github.lnyocly.ai4j.config;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstr"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/constant/Constants.java",
    "chars": 534,
    "preview": "package io.github.lnyocly.ai4j.constant;\n\n/**\n * @Author cly\n * @Description TODO\n * @Date 2024/8/11 0:19\n */\npublic cla"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/convert/audio/AudioParameterConvert.java",
    "chars": 191,
    "preview": "package io.github.lnyocly.ai4j.convert.audio;\n\n/**\n * @Author cly\n * @Description 处理请求参数。 由统一的OpenAi音频格式--->其它模型格式\n * @D"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/convert/audio/AudioResultConvert.java",
    "chars": 193,
    "preview": "package io.github.lnyocly.ai4j.convert.audio;\n\n/**\n * @Author cly\n * @Description 返回结果统一处理。 其它模型音频返回格式--->统一的OpenAi返回格式\n"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/convert/chat/ParameterConvert.java",
    "chars": 320,
    "preview": "package io.github.lnyocly.ai4j.convert.chat;\n\nimport io.github.lnyocly.ai4j.platform.openai.chat.entity.ChatCompletion;\n"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/convert/chat/ResultConvert.java",
    "chars": 491,
    "preview": "package io.github.lnyocly.ai4j.convert.chat;\n\nimport io.github.lnyocly.ai4j.listener.SseListener;\nimport io.github.lnyoc"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/convert/embedding/EmbeddingParameterConvert.java",
    "chars": 287,
    "preview": "package io.github.lnyocly.ai4j.convert.embedding;\n\n\nimport io.github.lnyocly.ai4j.platform.openai.embedding.entity.Embed"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/convert/embedding/EmbeddingResultConvert.java",
    "chars": 272,
    "preview": "package io.github.lnyocly.ai4j.convert.embedding;\n\nimport io.github.lnyocly.ai4j.platform.openai.embedding.entity.Embedd"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/document/RecursiveCharacterTextSplitter.java",
    "chars": 4492,
    "preview": "package io.github.lnyocly.ai4j.document;\n\nimport lombok.extern.slf4j.Slf4j;\nimport java.util.ArrayList;\nimport java.util"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/document/TikaUtil.java",
    "chars": 2591,
    "preview": "package io.github.lnyocly.ai4j.document;\n\nimport org.apache.tika.Tika;\nimport org.apache.tika.exception.TikaException;\ni"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/exception/Ai4jException.java",
    "chars": 335,
    "preview": "package io.github.lnyocly.ai4j.exception;\n\n/**\n * Base runtime exception for ai4j shared abstractions.\n */\npublic class "
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/exception/CommonException.java",
    "chars": 223,
    "preview": "package io.github.lnyocly.ai4j.exception;\n\n/**\n * Legacy exception kept for 1.x compatibility.\n */\npublic class CommonEx"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/exception/chain/AbstractErrorHandler.java",
    "chars": 630,
    "preview": "package io.github.lnyocly.ai4j.exception.chain;\n\nimport io.github.lnyocly.ai4j.exception.error.Error;\nimport io.github.l"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/exception/chain/ErrorHandler.java",
    "chars": 1436,
    "preview": "package io.github.lnyocly.ai4j.exception.chain;\n\nimport io.github.lnyocly.ai4j.exception.chain.impl.HunyuanErrorHandler;"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/exception/chain/IErrorHandler.java",
    "chars": 349,
    "preview": "package io.github.lnyocly.ai4j.exception.chain;\n\nimport io.github.lnyocly.ai4j.exception.error.Error;\nimport io.github.l"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/exception/chain/impl/HunyuanErrorHandler.java",
    "chars": 1376,
    "preview": "package io.github.lnyocly.ai4j.exception.chain.impl;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.e"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/exception/chain/impl/OpenAiErrorHandler.java",
    "chars": 1084,
    "preview": "package io.github.lnyocly.ai4j.exception.chain.impl;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.e"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/exception/chain/impl/UnknownErrorHandler.java",
    "chars": 593,
    "preview": "package io.github.lnyocly.ai4j.exception.chain.impl;\n\nimport io.github.lnyocly.ai4j.exception.chain.AbstractErrorHandler"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/exception/error/Error.java",
    "chars": 380,
    "preview": "package io.github.lnyocly.ai4j.exception.error;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoA"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/exception/error/HunyuanError.java",
    "chars": 753,
    "preview": "package io.github.lnyocly.ai4j.exception.error;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoA"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/exception/error/OpenAiError.java",
    "chars": 749,
    "preview": "package io.github.lnyocly.ai4j.exception.error;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.Get"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/interceptor/ContentTypeInterceptor.java",
    "chars": 2120,
    "preview": "package io.github.lnyocly.ai4j.interceptor;\n\nimport okhttp3.Interceptor;\nimport okhttp3.MediaType;\nimport okhttp3.Respon"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/interceptor/ErrorInterceptor.java",
    "chars": 6255,
    "preview": "package io.github.lnyocly.ai4j.interceptor;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONObject;"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/listener/AbstractManagedStreamListener.java",
    "chars": 7121,
    "preview": "package io.github.lnyocly.ai4j.listener;\n\nimport io.github.lnyocly.ai4j.exception.CommonException;\nimport lombok.Getter;"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/listener/ImageSseListener.java",
    "chars": 2860,
    "preview": "package io.github.lnyocly.ai4j.listener;\n\nimport io.github.lnyocly.ai4j.platform.openai.image.entity.ImageData;\nimport i"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/listener/ManagedStreamListener.java",
    "chars": 438,
    "preview": "package io.github.lnyocly.ai4j.listener;\n\npublic interface ManagedStreamListener {\n\n    void awaitCompletion(StreamExecu"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/listener/RealtimeListener.java",
    "chars": 1700,
    "preview": "package io.github.lnyocly.ai4j.listener;\n\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.Response;\nimport okhttp3.WebS"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/listener/ResponseSseListener.java",
    "chars": 5469,
    "preview": "package io.github.lnyocly.ai4j.listener;\n\nimport io.github.lnyocly.ai4j.platform.openai.response.entity.Response;\nimport"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/listener/SseListener.java",
    "chars": 17668,
    "preview": "package io.github.lnyocly.ai4j.listener;\n\nimport cn.hutool.core.util.StrUtil;\nimport com.fasterxml.jackson.core.JsonProc"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/listener/StreamExecutionOptions.java",
    "chars": 972,
    "preview": "package io.github.lnyocly.ai4j.listener;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\ni"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/listener/StreamExecutionSupport.java",
    "chars": 3962,
    "preview": "package io.github.lnyocly.ai4j.listener;\n\npublic final class StreamExecutionSupport {\n\n    public static final String DE"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/annotation/McpParameter.java",
    "chars": 548,
    "preview": "package io.github.lnyocly.ai4j.mcp.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * @Author cly\n * @Description MCP参数"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/annotation/McpPrompt.java",
    "chars": 662,
    "preview": "package io.github.lnyocly.ai4j.mcp.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Ret"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/annotation/McpPromptParameter.java",
    "chars": 642,
    "preview": "package io.github.lnyocly.ai4j.mcp.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Ret"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/annotation/McpResource.java",
    "chars": 832,
    "preview": "package io.github.lnyocly.ai4j.mcp.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Ret"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/annotation/McpResourceParameter.java",
    "chars": 589,
    "preview": "package io.github.lnyocly.ai4j.mcp.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Ret"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/annotation/McpService.java",
    "chars": 673,
    "preview": "package io.github.lnyocly.ai4j.mcp.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * @Author cly\n * @Description MCP服务"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/annotation/McpTool.java",
    "chars": 491,
    "preview": "package io.github.lnyocly.ai4j.mcp.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * @Author cly\n * @Description MCP工具"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/client/McpClient.java",
    "chars": 22558,
    "preview": "package io.github.lnyocly.ai4j.mcp.client;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.mcp.entity."
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/client/McpClientResponseSupport.java",
    "chars": 10602,
    "preview": "package io.github.lnyocly.ai4j.mcp.client;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.mcp.entity."
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/config/FileMcpConfigSource.java",
    "chars": 5019,
    "preview": "package io.github.lnyocly.ai4j.mcp.config;\n\nimport com.alibaba.fastjson2.JSON;\nimport org.slf4j.Logger;\nimport org.slf4j"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/config/McpConfigIO.java",
    "chars": 2787,
    "preview": "package io.github.lnyocly.ai4j.mcp.config;\n\nimport com.alibaba.fastjson2.JSON;\n\nimport java.io.ByteArrayOutputStream;\nim"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/config/McpConfigManager.java",
    "chars": 5295,
    "preview": "package io.github.lnyocly.ai4j.mcp.config;\n\nimport io.github.lnyocly.ai4j.mcp.transport.McpTransportFactory;\nimport io.g"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/config/McpConfigSource.java",
    "chars": 1019,
    "preview": "package io.github.lnyocly.ai4j.mcp.config;\n\nimport java.util.Map;\n\n/**\n * @Author cly\n * @Description MCP配置源接口,支持多种配置来源("
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/config/McpServerConfig.java",
    "chars": 3264,
    "preview": "package io.github.lnyocly.ai4j.mcp.config;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.Data;\n\ni"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpError.java",
    "chars": 2969,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpInitializeResponse.java",
    "chars": 697,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpMessage.java",
    "chars": 1993,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport com.fasterxml.jac"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpNotification.java",
    "chars": 555,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimen"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpPrompt.java",
    "chars": 656,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpPromptResult.java",
    "chars": 622,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpRequest.java",
    "chars": 537,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimen"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpResource.java",
    "chars": 786,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpResourceContent.java",
    "chars": 617,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpResponse.java",
    "chars": 649,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimen"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpRoot.java",
    "chars": 602,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpSamplingRequest.java",
    "chars": 878,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpSamplingResult.java",
    "chars": 619,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpServerInfo.java",
    "chars": 799,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpServerReference.java",
    "chars": 2930,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport io.github.lnyocly.ai4j.mcp.util.McpTypeSupport;\nimport lombok.AllArgs"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpTool.java",
    "chars": 672,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpToolDefinition.java",
    "chars": 860,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/entity/McpToolResult.java",
    "chars": 804,
    "preview": "package io.github.lnyocly.ai4j.mcp.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsC"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/gateway/McpGateway.java",
    "chars": 19382,
    "preview": "package io.github.lnyocly.ai4j.mcp.gateway;\n\nimport io.github.lnyocly.ai4j.mcp.client.McpClient;\nimport io.github.lnyocl"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/gateway/McpGatewayClientFactory.java",
    "chars": 1730,
    "preview": "package io.github.lnyocly.ai4j.mcp.gateway;\n\nimport io.github.lnyocly.ai4j.mcp.client.McpClient;\nimport io.github.lnyocl"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/gateway/McpGatewayConfigSourceBinding.java",
    "chars": 3192,
    "preview": "package io.github.lnyocly.ai4j.mcp.gateway;\n\nimport io.github.lnyocly.ai4j.mcp.client.McpClient;\nimport io.github.lnyocl"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/gateway/McpGatewayKeySupport.java",
    "chars": 1236,
    "preview": "package io.github.lnyocly.ai4j.mcp.gateway;\n\n/**\n * MCP gateway key 规则辅助类\n */\npublic final class McpGatewayKeySupport {\n"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/gateway/McpGatewayToolRegistry.java",
    "chars": 3865,
    "preview": "package io.github.lnyocly.ai4j.mcp.gateway;\n\nimport io.github.lnyocly.ai4j.mcp.client.McpClient;\nimport io.github.lnyocl"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/server/McpHttpServerSupport.java",
    "chars": 2808,
    "preview": "package io.github.lnyocly.ai4j.mcp.server;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.sun.net.httpserver.HttpExchang"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/server/McpServer.java",
    "chars": 845,
    "preview": "package io.github.lnyocly.ai4j.mcp.server;\n\nimport java.util.concurrent.CompletableFuture;\n\n/**\n * MCP服务器公共接口\n * 定义所有MCP"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/server/McpServerEngine.java",
    "chars": 17617,
    "preview": "package io.github.lnyocly.ai4j.mcp.server;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.mcp.entity."
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/server/McpServerFactory.java",
    "chars": 6907,
    "preview": "package io.github.lnyocly.ai4j.mcp.server;\n\nimport io.github.lnyocly.ai4j.mcp.util.McpTypeSupport;\nimport org.slf4j.Logg"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/server/McpServerSessionState.java",
    "chars": 773,
    "preview": "package io.github.lnyocly.ai4j.mcp.server;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n *"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/server/McpServerSessionSupport.java",
    "chars": 1090,
    "preview": "package io.github.lnyocly.ai4j.mcp.server;\n\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.function.Fun"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/server/SseMcpServer.java",
    "chars": 17004,
    "preview": "package io.github.lnyocly.ai4j.mcp.server;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.sun.net.httpserver.HttpExchang"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/server/StdioMcpServer.java",
    "chars": 5150,
    "preview": "package io.github.lnyocly.ai4j.mcp.server;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.mcp.entity."
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/server/StreamableHttpMcpServer.java",
    "chars": 16770,
    "preview": "package io.github.lnyocly.ai4j.mcp.server;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.sun.net.httpserver.HttpExchang"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/transport/McpTransport.java",
    "chars": 1535,
    "preview": "package io.github.lnyocly.ai4j.mcp.transport;\n\nimport io.github.lnyocly.ai4j.mcp.entity.McpMessage;\n\nimport java.util.co"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/transport/McpTransportFactory.java",
    "chars": 4820,
    "preview": "package io.github.lnyocly.ai4j.mcp.transport;\n\nimport io.github.lnyocly.ai4j.mcp.util.McpTypeSupport;\nimport org.slf4j.L"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/transport/McpTransportSupport.java",
    "chars": 4399,
    "preview": "package io.github.lnyocly.ai4j.mcp.transport;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONObjec"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/transport/SseTransport.java",
    "chars": 22039,
    "preview": "package io.github.lnyocly.ai4j.mcp.transport;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.mcp.enti"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/transport/StdioTransport.java",
    "chars": 10390,
    "preview": "package io.github.lnyocly.ai4j.mcp.transport;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.mcp.enti"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/transport/StreamableHttpTransport.java",
    "chars": 10614,
    "preview": "package io.github.lnyocly.ai4j.mcp.transport;\n\nimport io.github.lnyocly.ai4j.mcp.entity.McpMessage;\nimport com.alibaba.f"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/transport/TransportConfig.java",
    "chars": 7467,
    "preview": "package io.github.lnyocly.ai4j.mcp.transport;\n\nimport io.github.lnyocly.ai4j.mcp.config.McpServerConfig;\nimport io.githu"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/util/McpMessageCodec.java",
    "chars": 1864,
    "preview": "package io.github.lnyocly.ai4j.mcp.util;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.mcp.entity.Mc"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/util/McpPromptAdapter.java",
    "chars": 9538,
    "preview": "package io.github.lnyocly.ai4j.mcp.util;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.mcp.annotatio"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/util/McpResourceAdapter.java",
    "chars": 9415,
    "preview": "package io.github.lnyocly.ai4j.mcp.util;\n\nimport io.github.lnyocly.ai4j.mcp.annotation.McpResource;\nimport io.github.lny"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/util/McpToolAdapter.java",
    "chars": 14774,
    "preview": "package io.github.lnyocly.ai4j.mcp.util;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.mcp.annotatio"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/util/McpToolConversionSupport.java",
    "chars": 2907,
    "preview": "package io.github.lnyocly.ai4j.mcp.util;\n\nimport io.github.lnyocly.ai4j.mcp.entity.McpToolDefinition;\nimport io.github.l"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/mcp/util/McpTypeSupport.java",
    "chars": 3247,
    "preview": "package io.github.lnyocly.ai4j.mcp.util;\n\nimport io.github.lnyocly.ai4j.mcp.config.McpServerConfig;\nimport io.github.lny"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/ChatMemory.java",
    "chars": 868,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport io.github.lnyocly.ai4j.platform.openai.chat.entity.ChatMessage;\nimport io"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/ChatMemoryItem.java",
    "chars": 9848,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport io.github.lnyocly.ai4j.platform.openai.chat.entity.ChatMessage;\nimport io"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/ChatMemoryPolicy.java",
    "chars": 163,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport java.util.List;\n\npublic interface ChatMemoryPolicy {\n\n    List<ChatMemory"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/ChatMemorySnapshot.java",
    "chars": 743,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimp"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/ChatMemorySummarizer.java",
    "chars": 139,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\npublic interface ChatMemorySummarizer {\n\n    String summarize(ChatMemorySummaryR"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/ChatMemorySummaryRequest.java",
    "chars": 1003,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimp"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/InMemoryChatMemory.java",
    "chars": 3809,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport io.github.lnyocly.ai4j.platform.openai.chat.entity.ChatMessage;\nimport io"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/JdbcChatMemory.java",
    "chars": 10984,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.ai4j.platform.openai"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/JdbcChatMemoryConfig.java",
    "chars": 680,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimp"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/MessageWindowChatMemoryPolicy.java",
    "chars": 1466,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport io.github.lnyocly.ai4j.platform.openai.chat.enums.ChatMessageType;\n\nimpor"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/SummaryChatMemoryPolicy.java",
    "chars": 7949,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport io.github.lnyocly.ai4j.platform.openai.chat.enums.ChatMessageType;\n\nimpor"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/SummaryChatMemoryPolicyConfig.java",
    "chars": 710,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport io.github.lnyocly.ai4j.platform.openai.chat.enums.ChatMessageType;\nimport"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/memory/UnboundedChatMemoryPolicy.java",
    "chars": 519,
    "preview": "package io.github.lnyocly.ai4j.memory;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class UnboundedChatMe"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/network/ConnectionPoolProvider.java",
    "chars": 240,
    "preview": "package io.github.lnyocly.ai4j.network;\n\nimport okhttp3.ConnectionPool;\n\n/**\n * @Author cly\n * @Description ConnectionPo"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/network/DispatcherProvider.java",
    "chars": 220,
    "preview": "package io.github.lnyocly.ai4j.network;\n\nimport okhttp3.Dispatcher;\n\n/**\n * @Author cly\n * @Description Dispatcher提供器\n *"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/network/OkHttpUtil.java",
    "chars": 1697,
    "preview": "package io.github.lnyocly.ai4j.network;\n\nimport javax.net.ssl.*;\nimport java.security.KeyManagementException;\nimport jav"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/network/UrlUtils.java",
    "chars": 1149,
    "preview": "package io.github.lnyocly.ai4j.network;\n\n/**\n * @Author cly\n * @Description 用于验证、处理\n * @Date 2024/9/19 14:40\n */\npublic "
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/network/impl/DefaultConnectionPoolProvider.java",
    "chars": 410,
    "preview": "package io.github.lnyocly.ai4j.network.impl;\n\nimport io.github.lnyocly.ai4j.network.ConnectionPoolProvider;\nimport okhtt"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/network/impl/DefaultDispatcherProvider.java",
    "chars": 378,
    "preview": "package io.github.lnyocly.ai4j.network.impl;\n\nimport io.github.lnyocly.ai4j.network.DispatcherProvider;\nimport okhttp3.D"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/baichuan/chat/BaichuanChatService.java",
    "chars": 16402,
    "preview": "package io.github.lnyocly.ai4j.platform.baichuan.chat;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimpor"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/baichuan/chat/entity/BaichuanChatCompletion.java",
    "chars": 2660,
    "preview": "package io.github.lnyocly.ai4j.platform.baichuan.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonAnyGetter;\nim"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/baichuan/chat/entity/BaichuanChatCompletionResponse.java",
    "chars": 761,
    "preview": "package io.github.lnyocly.ai4j.platform.baichuan.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonIgnorePropert"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/dashscope/DashScopeChatService.java",
    "chars": 15218,
    "preview": "package io.github.lnyocly.ai4j.platform.dashscope;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.uti"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/dashscope/entity/DashScopeResult.java",
    "chars": 434,
    "preview": "package io.github.lnyocly.ai4j.platform.dashscope.entity;\n\nimport com.alibaba.dashscope.aigc.generation.GenerationResult"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/dashscope/response/DashScopeResponsesService.java",
    "chars": 8593,
    "preview": "package io.github.lnyocly.ai4j.platform.dashscope.response;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport "
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/dashscope/util/MessageUtil.java",
    "chars": 4740,
    "preview": "package io.github.lnyocly.ai4j.platform.dashscope.util;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.coll"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/deepseek/chat/DeepSeekChatService.java",
    "chars": 16909,
    "preview": "package io.github.lnyocly.ai4j.platform.deepseek.chat;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimpor"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/deepseek/chat/entity/DeepSeekChatCompletion.java",
    "chars": 4727,
    "preview": "package io.github.lnyocly.ai4j.platform.deepseek.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonAnyGetter;\nim"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/deepseek/chat/entity/DeepSeekChatCompletionResponse.java",
    "chars": 1305,
    "preview": "package io.github.lnyocly.ai4j.platform.deepseek.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonIgnorePropert"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/doubao/chat/DoubaoChatService.java",
    "chars": 16899,
    "preview": "package io.github.lnyocly.ai4j.platform.doubao.chat;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport "
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/doubao/chat/entity/DoubaoChatCompletion.java",
    "chars": 4416,
    "preview": "package io.github.lnyocly.ai4j.platform.doubao.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonAnyGetter;\nimpo"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/doubao/chat/entity/DoubaoChatCompletionResponse.java",
    "chars": 1220,
    "preview": "package io.github.lnyocly.ai4j.platform.doubao.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonIgnorePropertie"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/doubao/image/DoubaoImageService.java",
    "chars": 8207,
    "preview": "package io.github.lnyocly.ai4j.platform.doubao.image;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io.git"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/doubao/image/entity/DoubaoImageGenerationRequest.java",
    "chars": 1005,
    "preview": "package io.github.lnyocly.ai4j.platform.doubao.image.entity;\n\nimport com.fasterxml.jackson.annotation.JsonAnyGetter;\nimp"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/doubao/rerank/DoubaoRerankService.java",
    "chars": 8569,
    "preview": "package io.github.lnyocly.ai4j.platform.doubao.rerank;\n\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.faste"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/doubao/response/DoubaoResponsesService.java",
    "chars": 8382,
    "preview": "package io.github.lnyocly.ai4j.platform.doubao.response;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io."
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/hunyuan/HunyuanConstant.java",
    "chars": 279,
    "preview": "package io.github.lnyocly.ai4j.platform.hunyuan;\n\n/**\n * @Author cly\n * @Description 腾讯混元常量\n * @Date 2024/8/30 19:30\n */"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/hunyuan/chat/HunyuanChatService.java",
    "chars": 22794,
    "preview": "package io.github.lnyocly.ai4j.platform.hunyuan.chat;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.J"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/hunyuan/chat/entity/HunyuanChatCompletion.java",
    "chars": 3034,
    "preview": "package io.github.lnyocly.ai4j.platform.hunyuan.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonAnyGetter;\nimp"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/hunyuan/chat/entity/HunyuanChatCompletionResponse.java",
    "chars": 1232,
    "preview": "package io.github.lnyocly.ai4j.platform.hunyuan.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperti"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/hunyuan/support/HunyuanJsonUtil.java",
    "chars": 3282,
    "preview": "package io.github.lnyocly.ai4j.platform.hunyuan.support;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/jina/rerank/JinaRerankService.java",
    "chars": 835,
    "preview": "package io.github.lnyocly.ai4j.platform.jina.rerank;\n\nimport io.github.lnyocly.ai4j.config.JinaConfig;\nimport io.github."
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/lingyi/chat/LingyiChatService.java",
    "chars": 15588,
    "preview": "package io.github.lnyocly.ai4j.platform.lingyi.chat;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport "
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/lingyi/chat/entity/LingyiChatCompletion.java",
    "chars": 3157,
    "preview": "package io.github.lnyocly.ai4j.platform.lingyi.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonAnyGetter;\nimpo"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/lingyi/chat/entity/LingyiChatCompletionResponse.java",
    "chars": 1175,
    "preview": "package io.github.lnyocly.ai4j.platform.lingyi.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonIgnorePropertie"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/minimax/chat/MinimaxChatService.java",
    "chars": 16713,
    "preview": "package io.github.lnyocly.ai4j.platform.minimax.chat;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/minimax/chat/entity/MinimaxChatCompletion.java",
    "chars": 3200,
    "preview": "package io.github.lnyocly.ai4j.platform.minimax.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonAnyGetter;\nimp"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/minimax/chat/entity/MinimaxChatCompletionResponse.java",
    "chars": 1212,
    "preview": "package io.github.lnyocly.ai4j.platform.minimax.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperti"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/moonshot/chat/MoonshotChatService.java",
    "chars": 17036,
    "preview": "package io.github.lnyocly.ai4j.platform.moonshot.chat;\n\nimport com.alibaba.fastjson2.JSONObject;\nimport com.alibaba.fast"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/moonshot/chat/entity/MoonshotChatCompletion.java",
    "chars": 4073,
    "preview": "package io.github.lnyocly.ai4j.platform.moonshot.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonAnyGetter;\nim"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/moonshot/chat/entity/MoonshotChatCompletionResponse.java",
    "chars": 1301,
    "preview": "package io.github.lnyocly.ai4j.platform.moonshot.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonIgnorePropert"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/ollama/chat/OllamaAiChatService.java",
    "chars": 25588,
    "preview": "package io.github.lnyocly.ai4j.platform.ollama.chat;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JS"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/ollama/chat/entity/OllamaChatCompletion.java",
    "chars": 1435,
    "preview": "package io.github.lnyocly.ai4j.platform.ollama.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonAnyGetter;\nimpo"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/ollama/chat/entity/OllamaChatCompletionResponse.java",
    "chars": 1212,
    "preview": "package io.github.lnyocly.ai4j.platform.ollama.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonIgnorePropertie"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/ollama/chat/entity/OllamaMessage.java",
    "chars": 722,
    "preview": "package io.github.lnyocly.ai4j.platform.ollama.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimpor"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/ollama/chat/entity/OllamaOptions.java",
    "chars": 810,
    "preview": "package io.github.lnyocly.ai4j.platform.ollama.chat.entity;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimpor"
  },
  {
    "path": "ai4j/src/main/java/io/github/lnyocly/ai4j/platform/ollama/embedding/OllamaEmbeddingService.java",
    "chars": 4860,
    "preview": "package io.github.lnyocly.ai4j.platform.ollama.embedding;\n\nimport com.alibaba.fastjson2.JSON;\nimport io.github.lnyocly.a"
  }
]

// ... and 1075 more files (download for full content)

About this extraction

This page contains the full source code of the LnYo-Cly/ai4j GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1275 files (5.4 MB), approximately 1.5M tokens, and a symbol index with 8443 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!