@gt-fe/eap-runtime 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +323 -0
- package/dist/api/handlers/index.d.ts +3 -0
- package/dist/api/handlers/index.js +4 -0
- package/dist/api/handlers/invoke.handler.d.ts +77 -0
- package/dist/api/handlers/invoke.handler.js +411 -0
- package/dist/api/handlers/messages.handler.d.ts +53 -0
- package/dist/api/handlers/messages.handler.js +80 -0
- package/dist/api/handlers/stream.handler.d.ts +92 -0
- package/dist/api/handlers/stream.handler.js +432 -0
- package/dist/api/index.d.ts +3 -0
- package/dist/api/index.js +4 -0
- package/dist/api/middleware/auth.middleware.d.ts +96 -0
- package/dist/api/middleware/auth.middleware.js +158 -0
- package/dist/api/middleware/index.d.ts +1 -0
- package/dist/api/middleware/index.js +2 -0
- package/dist/api/routes/agent.routes.d.ts +44 -0
- package/dist/api/routes/agent.routes.js +204 -0
- package/dist/api/routes/index.d.ts +3 -0
- package/dist/api/routes/index.js +4 -0
- package/dist/api/routes/session.routes.d.ts +82 -0
- package/dist/api/routes/session.routes.js +169 -0
- package/dist/api/routes/task.routes.d.ts +75 -0
- package/dist/api/routes/task.routes.js +108 -0
- package/dist/checkpoint/checkpoint-serializer.d.ts +58 -0
- package/dist/checkpoint/checkpoint-serializer.js +81 -0
- package/dist/checkpoint/composite-checkpoint-saver.d.ts +42 -0
- package/dist/checkpoint/composite-checkpoint-saver.js +118 -0
- package/dist/checkpoint/contracts/checkpoint-saver.contract.d.ts +65 -0
- package/dist/checkpoint/contracts/checkpoint-saver.contract.js +12 -0
- package/dist/checkpoint/contracts/index.d.ts +1 -0
- package/dist/checkpoint/contracts/index.js +1 -0
- package/dist/checkpoint/file-checkpoint-saver.d.ts +19 -0
- package/dist/checkpoint/file-checkpoint-saver.js +98 -0
- package/dist/checkpoint/hybrid-checkpoint-saver.d.ts +130 -0
- package/dist/checkpoint/hybrid-checkpoint-saver.js +211 -0
- package/dist/checkpoint/in-memory-checkpoint-saver.d.ts +14 -0
- package/dist/checkpoint/in-memory-checkpoint-saver.js +46 -0
- package/dist/checkpoint/index.d.ts +16 -0
- package/dist/checkpoint/index.js +13 -0
- package/dist/checkpoint/mongo-checkpoint-saver.d.ts +38 -0
- package/dist/checkpoint/mongo-checkpoint-saver.js +56 -0
- package/dist/checkpoint/pg-checkpoint-saver.d.ts +59 -0
- package/dist/checkpoint/pg-checkpoint-saver.js +140 -0
- package/dist/checkpoint/redis-checkpoint-saver.d.ts +68 -0
- package/dist/checkpoint/redis-checkpoint-saver.js +173 -0
- package/dist/checkpoint/restore-checkpoint.d.ts +33 -0
- package/dist/checkpoint/restore-checkpoint.js +33 -0
- package/dist/common/agent-code.d.ts +10 -0
- package/dist/common/agent-code.js +12 -0
- package/dist/common/concurrency.d.ts +79 -0
- package/dist/common/concurrency.js +121 -0
- package/dist/common/health.d.ts +40 -0
- package/dist/common/health.js +37 -0
- package/dist/common/index.d.ts +5 -0
- package/dist/common/index.js +5 -0
- package/dist/common/logger.d.ts +34 -0
- package/dist/common/logger.js +38 -0
- package/dist/common/queue-consumer.d.ts +125 -0
- package/dist/common/queue-consumer.js +159 -0
- package/dist/common/trace-id.d.ts +2 -0
- package/dist/common/trace-id.js +8 -0
- package/dist/common/types.d.ts +104 -0
- package/dist/common/types.js +14 -0
- package/dist/contracts/index.d.ts +11 -0
- package/dist/contracts/index.js +10 -0
- package/dist/contracts/permission-checker.d.ts +10 -0
- package/dist/contracts/permission-checker.js +4 -0
- package/dist/contracts/trace-collector.d.ts +211 -0
- package/dist/contracts/trace-collector.js +13 -0
- package/dist/governance/governance-client.d.ts +38 -0
- package/dist/governance/governance-client.js +95 -0
- package/dist/governance/index.d.ts +7 -0
- package/dist/governance/index.js +5 -0
- package/dist/governance/permission-guard.d.ts +19 -0
- package/dist/governance/permission-guard.js +59 -0
- package/dist/graph/adapters/index.d.ts +3 -0
- package/dist/graph/adapters/index.js +3 -0
- package/dist/graph/adapters/langgraph-checkpointer.d.ts +40 -0
- package/dist/graph/adapters/langgraph-checkpointer.js +211 -0
- package/dist/graph/adapters/langgraph.adapter.d.ts +190 -0
- package/dist/graph/adapters/langgraph.adapter.js +1303 -0
- package/dist/graph/adapters/subgraph-compiler.d.ts +39 -0
- package/dist/graph/adapters/subgraph-compiler.js +248 -0
- package/dist/graph/condition-evaluator.d.ts +57 -0
- package/dist/graph/condition-evaluator.js +162 -0
- package/dist/graph/contracts/executable-graph.d.ts +340 -0
- package/dist/graph/contracts/executable-graph.js +10 -0
- package/dist/graph/contracts/index.d.ts +2 -0
- package/dist/graph/contracts/index.js +2 -0
- package/dist/graph/contracts/state-graph.contract.d.ts +76 -0
- package/dist/graph/contracts/state-graph.contract.js +11 -0
- package/dist/graph/hitl/hitl-handler.d.ts +199 -0
- package/dist/graph/hitl/hitl-handler.js +480 -0
- package/dist/graph/hitl/index.d.ts +1 -0
- package/dist/graph/hitl/index.js +1 -0
- package/dist/graph/index.d.ts +7 -0
- package/dist/graph/index.js +7 -0
- package/dist/graph/nodes/index.d.ts +2 -0
- package/dist/graph/nodes/index.js +2 -0
- package/dist/graph/nodes/llm-node.d.ts +182 -0
- package/dist/graph/nodes/llm-node.js +281 -0
- package/dist/graph/nodes/skill-bind-node.d.ts +32 -0
- package/dist/graph/nodes/skill-bind-node.js +116 -0
- package/dist/graph/nodes/tool-node.d.ts +75 -0
- package/dist/graph/nodes/tool-node.js +324 -0
- package/dist/graph/resolve-graph-prompt.d.ts +5 -0
- package/dist/graph/resolve-graph-prompt.js +75 -0
- package/dist/graph/retry/budget-aware-retry.d.ts +91 -0
- package/dist/graph/retry/budget-aware-retry.js +126 -0
- package/dist/graph/retry/index.d.ts +9 -0
- package/dist/graph/retry/index.js +8 -0
- package/dist/graph/retry/node-retry.d.ts +123 -0
- package/dist/graph/retry/node-retry.js +235 -0
- package/dist/graph/skill-audit-recorder.d.ts +126 -0
- package/dist/graph/skill-audit-recorder.js +114 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +32 -0
- package/dist/memory/compression/compression-stats.d.ts +109 -0
- package/dist/memory/compression/compression-stats.js +144 -0
- package/dist/memory/compression/compression.repository.d.ts +62 -0
- package/dist/memory/compression/compression.repository.js +71 -0
- package/dist/memory/compression/index.d.ts +10 -0
- package/dist/memory/compression/index.js +15 -0
- package/dist/memory/compression/llm-summarize.d.ts +58 -0
- package/dist/memory/compression/llm-summarize.js +192 -0
- package/dist/memory/compression/sliding-window.compression.d.ts +60 -0
- package/dist/memory/compression/sliding-window.compression.js +175 -0
- package/dist/memory/index.d.ts +4 -0
- package/dist/memory/index.js +7 -0
- package/dist/memory/long-term-memory.service.d.ts +94 -0
- package/dist/memory/long-term-memory.service.js +120 -0
- package/dist/memory/message-compression.service.d.ts +128 -0
- package/dist/memory/message-compression.service.js +69 -0
- package/dist/memory/pg-memory.repository.d.ts +44 -0
- package/dist/memory/pg-memory.repository.js +108 -0
- package/dist/memory/semantic-retrieval.service.d.ts +148 -0
- package/dist/memory/semantic-retrieval.service.js +238 -0
- package/dist/providers/echo-llm-provider.d.ts +10 -0
- package/dist/providers/echo-llm-provider.js +87 -0
- package/dist/providers/http-llm-provider.d.ts +35 -0
- package/dist/providers/http-llm-provider.js +404 -0
- package/dist/providers/index.d.ts +7 -0
- package/dist/providers/index.js +5 -0
- package/dist/providers/local-llm-provider.d.ts +27 -0
- package/dist/providers/local-llm-provider.js +105 -0
- package/dist/providers/resolve-llm-model.d.ts +13 -0
- package/dist/providers/resolve-llm-model.js +30 -0
- package/dist/providers/routing-llm-provider.d.ts +28 -0
- package/dist/providers/routing-llm-provider.js +79 -0
- package/dist/registry/agent-models.d.ts +1 -0
- package/dist/registry/agent-models.js +1 -0
- package/dist/registry/agent-registry-client.d.ts +56 -0
- package/dist/registry/agent-registry-client.js +36 -0
- package/dist/registry/definition-cache.d.ts +37 -0
- package/dist/registry/definition-cache.js +82 -0
- package/dist/registry/deployment-snapshot.d.ts +99 -0
- package/dist/registry/deployment-snapshot.js +542 -0
- package/dist/registry/graph-loader.d.ts +134 -0
- package/dist/registry/graph-loader.js +985 -0
- package/dist/registry/index.d.ts +9 -0
- package/dist/registry/index.js +9 -0
- package/dist/registry/preload-errors.d.ts +13 -0
- package/dist/registry/preload-errors.js +35 -0
- package/dist/registry/preload-flags.d.ts +22 -0
- package/dist/registry/preload-flags.js +44 -0
- package/dist/registry/skill-io-guard.d.ts +25 -0
- package/dist/registry/skill-io-guard.js +98 -0
- package/dist/registry/skill-tree.d.ts +27 -0
- package/dist/registry/skill-tree.js +183 -0
- package/dist/runtime/agent-runtime.d.ts +106 -0
- package/dist/runtime/agent-runtime.js +777 -0
- package/dist/runtime/dev-runtime.d.ts +69 -0
- package/dist/runtime/dev-runtime.js +199 -0
- package/dist/runtime/index.d.ts +4 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/storage-profile.d.ts +50 -0
- package/dist/runtime/storage-profile.js +138 -0
- package/dist/runtime/types.d.ts +120 -0
- package/dist/runtime/types.js +9 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.js +161 -0
- package/dist/session/compression-middleware.d.ts +126 -0
- package/dist/session/compression-middleware.js +230 -0
- package/dist/session/file-message.repository.d.ts +25 -0
- package/dist/session/file-message.repository.js +78 -0
- package/dist/session/file-session.repository.d.ts +72 -0
- package/dist/session/file-session.repository.js +212 -0
- package/dist/session/index.d.ts +13 -0
- package/dist/session/index.js +12 -0
- package/dist/session/message.service.d.ts +80 -0
- package/dist/session/message.service.js +128 -0
- package/dist/session/persist-turn-messages.d.ts +145 -0
- package/dist/session/persist-turn-messages.js +325 -0
- package/dist/session/pg-message.repository.d.ts +49 -0
- package/dist/session/pg-message.repository.js +149 -0
- package/dist/session/pg-session.repository.d.ts +46 -0
- package/dist/session/pg-session.repository.js +117 -0
- package/dist/session/session-context.service.d.ts +49 -0
- package/dist/session/session-context.service.js +66 -0
- package/dist/session/session.service.d.ts +194 -0
- package/dist/session/session.service.js +166 -0
- package/dist/sse/connection-event-logger.d.ts +21 -0
- package/dist/sse/connection-event-logger.js +33 -0
- package/dist/sse/contracts/index.d.ts +1 -0
- package/dist/sse/contracts/index.js +1 -0
- package/dist/sse/contracts/sse-emitter.contract.d.ts +74 -0
- package/dist/sse/contracts/sse-emitter.contract.js +11 -0
- package/dist/sse/event-buffer.d.ts +20 -0
- package/dist/sse/event-buffer.js +45 -0
- package/dist/sse/events/code-events.d.ts +19 -0
- package/dist/sse/events/code-events.js +9 -0
- package/dist/sse/events/collaboration-events.d.ts +37 -0
- package/dist/sse/events/collaboration-events.js +11 -0
- package/dist/sse/events/connection-events.d.ts +13 -0
- package/dist/sse/events/connection-events.js +9 -0
- package/dist/sse/events/file-events.d.ts +29 -0
- package/dist/sse/events/file-events.js +10 -0
- package/dist/sse/events/hitl-events.d.ts +33 -0
- package/dist/sse/events/hitl-events.js +10 -0
- package/dist/sse/events/index.d.ts +107 -0
- package/dist/sse/events/index.js +96 -0
- package/dist/sse/events/plan-events.d.ts +38 -0
- package/dist/sse/events/plan-events.js +11 -0
- package/dist/sse/events/reasoning-events.d.ts +35 -0
- package/dist/sse/events/reasoning-events.js +13 -0
- package/dist/sse/events/response-events.d.ts +25 -0
- package/dist/sse/events/response-events.js +12 -0
- package/dist/sse/events/session-events.d.ts +43 -0
- package/dist/sse/events/session-events.js +12 -0
- package/dist/sse/events/skill-events.d.ts +48 -0
- package/dist/sse/events/skill-events.js +11 -0
- package/dist/sse/events/stats-events.d.ts +44 -0
- package/dist/sse/events/stats-events.js +12 -0
- package/dist/sse/events/tool-events.d.ts +68 -0
- package/dist/sse/events/tool-events.js +14 -0
- package/dist/sse/index.d.ts +8 -0
- package/dist/sse/index.js +8 -0
- package/dist/sse/sse-connection-manager.d.ts +116 -0
- package/dist/sse/sse-connection-manager.js +185 -0
- package/dist/sse/sse-emitter.d.ts +108 -0
- package/dist/sse/sse-emitter.js +210 -0
- package/dist/sse/sse-heartbeat.d.ts +58 -0
- package/dist/sse/sse-heartbeat.js +76 -0
- package/dist/sse/trace-collector.d.ts +60 -0
- package/dist/sse/trace-collector.js +107 -0
- package/dist/task/contracts/index.d.ts +2 -0
- package/dist/task/contracts/index.js +1 -0
- package/dist/task/contracts/task-manager.contract.d.ts +160 -0
- package/dist/task/contracts/task-manager.contract.js +10 -0
- package/dist/task/index.d.ts +7 -0
- package/dist/task/index.js +5 -0
- package/dist/task/pg-task.repository.d.ts +47 -0
- package/dist/task/pg-task.repository.js +131 -0
- package/dist/task/task-progress-tracker.d.ts +67 -0
- package/dist/task/task-progress-tracker.js +80 -0
- package/dist/task/task-timeout.d.ts +70 -0
- package/dist/task/task-timeout.js +116 -0
- package/dist/task/task.service.d.ts +84 -0
- package/dist/task/task.service.js +233 -0
- package/dist/token/compression-budget-integration.d.ts +145 -0
- package/dist/token/compression-budget-integration.js +185 -0
- package/dist/token/context-window-budget.d.ts +113 -0
- package/dist/token/context-window-budget.js +134 -0
- package/dist/token/contracts/index.d.ts +1 -0
- package/dist/token/contracts/index.js +1 -0
- package/dist/token/contracts/token-budget.contract.d.ts +77 -0
- package/dist/token/contracts/token-budget.contract.js +11 -0
- package/dist/token/index.d.ts +12 -0
- package/dist/token/index.js +10 -0
- package/dist/token/pg-token-budget.repository.d.ts +39 -0
- package/dist/token/pg-token-budget.repository.js +116 -0
- package/dist/token/session-budget-checker.d.ts +54 -0
- package/dist/token/session-budget-checker.js +72 -0
- package/dist/token/token-budget-guard.d.ts +66 -0
- package/dist/token/token-budget-guard.js +97 -0
- package/dist/token/token-budget.service.d.ts +86 -0
- package/dist/token/token-budget.service.js +130 -0
- package/dist/token/token-detail-mode.d.ts +73 -0
- package/dist/token/token-detail-mode.js +107 -0
- package/dist/token/token-estimator.d.ts +80 -0
- package/dist/token/token-estimator.js +134 -0
- package/dist/token/token-stats.service.d.ts +88 -0
- package/dist/token/token-stats.service.js +94 -0
- package/dist/tool/create-tool-executor.d.ts +33 -0
- package/dist/tool/create-tool-executor.js +60 -0
- package/dist/tool/dev-http-executor.d.ts +18 -0
- package/dist/tool/dev-http-executor.js +96 -0
- package/dist/tool/dev-mcp-executor.d.ts +29 -0
- package/dist/tool/dev-mcp-executor.js +84 -0
- package/dist/tool/dev-tool-executor.d.ts +23 -0
- package/dist/tool/dev-tool-executor.js +55 -0
- package/dist/tool/file-artifact.d.ts +11 -0
- package/dist/tool/file-artifact.js +90 -0
- package/dist/tool/http-tool-executor.d.ts +17 -0
- package/dist/tool/http-tool-executor.js +158 -0
- package/dist/tool/index.d.ts +18 -0
- package/dist/tool/index.js +17 -0
- package/dist/tool/loaded-tool-definition.d.ts +35 -0
- package/dist/tool/loaded-tool-definition.js +9 -0
- package/dist/tool/local-mcp-client.d.ts +23 -0
- package/dist/tool/local-mcp-client.js +225 -0
- package/dist/tool/local-tool-executor.d.ts +37 -0
- package/dist/tool/local-tool-executor.js +249 -0
- package/dist/tool/mcp-tool-executor.d.ts +23 -0
- package/dist/tool/mcp-tool-executor.js +160 -0
- package/dist/tool/mock-tool-executor.d.ts +28 -0
- package/dist/tool/mock-tool-executor.js +65 -0
- package/dist/tool/system-prompt-builder.d.ts +114 -0
- package/dist/tool/system-prompt-builder.js +213 -0
- package/dist/tool/tool-confirmation.d.ts +29 -0
- package/dist/tool/tool-confirmation.js +81 -0
- package/dist/tool/tool-event-emitter.d.ts +58 -0
- package/dist/tool/tool-event-emitter.js +154 -0
- package/dist/tool/tool-execution-router.d.ts +25 -0
- package/dist/tool/tool-execution-router.js +50 -0
- package/dist/tool/tool-executor.interface.d.ts +85 -0
- package/dist/tool/tool-executor.interface.js +7 -0
- package/dist/tool/tool-orchestrator.d.ts +22 -0
- package/dist/tool/tool-orchestrator.js +104 -0
- package/dist/tool/tool-result-injector.d.ts +64 -0
- package/dist/tool/tool-result-injector.js +65 -0
- package/dist/utils/format-error.d.ts +4 -0
- package/dist/utils/format-error.js +4 -0
- package/dist/utils/http-error.d.ts +11 -0
- package/dist/utils/http-error.js +24 -0
- package/package.json +56 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostgresMemoryRepository — Memory 持久化 PostgreSQL 实现
|
|
3
|
+
*
|
|
4
|
+
* 基于 pg 连接池实现 IMemoryRepository 接口。
|
|
5
|
+
* 支持审计字段和软删除。
|
|
6
|
+
*
|
|
7
|
+
* @see design.md §1.3 memories 表
|
|
8
|
+
*/
|
|
9
|
+
import type { MemoryRecord, IMemoryRepository } from './long-term-memory.service.js';
|
|
10
|
+
/** pg Pool 抽象接口 */
|
|
11
|
+
export interface IPgPool {
|
|
12
|
+
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<{
|
|
13
|
+
rows: T[];
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export declare class PostgresMemoryRepository implements IMemoryRepository {
|
|
17
|
+
private readonly pool;
|
|
18
|
+
constructor(pool: IPgPool);
|
|
19
|
+
/**
|
|
20
|
+
* INSERT memory record with audit fields
|
|
21
|
+
*/
|
|
22
|
+
save(record: MemoryRecord): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* SELECT memories by user_id and agent_id
|
|
25
|
+
* Excludes soft-deleted records
|
|
26
|
+
*/
|
|
27
|
+
findByUserAndAgent(userId: string, agentCode: string, limit?: number): Promise<MemoryRecord[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Soft delete memory (implements IMemoryRepository.delete)
|
|
30
|
+
*/
|
|
31
|
+
delete(id: string): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Soft delete memory with audit
|
|
34
|
+
*/
|
|
35
|
+
softDelete(id: string, deletedBy: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* UPDATE memory record
|
|
38
|
+
*/
|
|
39
|
+
update(record: MemoryRecord): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* 将 PostgreSQL 行数据转换为 MemoryRecord
|
|
42
|
+
*/
|
|
43
|
+
private rowToRecord;
|
|
44
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostgresMemoryRepository — Memory 持久化 PostgreSQL 实现
|
|
3
|
+
*
|
|
4
|
+
* 基于 pg 连接池实现 IMemoryRepository 接口。
|
|
5
|
+
* 支持审计字段和软删除。
|
|
6
|
+
*
|
|
7
|
+
* @see design.md §1.3 memories 表
|
|
8
|
+
*/
|
|
9
|
+
// ─────────────────────────────────────────────
|
|
10
|
+
// PostgresMemoryRepository
|
|
11
|
+
// ─────────────────────────────────────────────
|
|
12
|
+
export class PostgresMemoryRepository {
|
|
13
|
+
pool;
|
|
14
|
+
constructor(pool) {
|
|
15
|
+
this.pool = pool;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* INSERT memory record with audit fields
|
|
19
|
+
*/
|
|
20
|
+
async save(record) {
|
|
21
|
+
const sql = `
|
|
22
|
+
INSERT INTO memories (id, user_id, agent_id, type, content, relevance_score, created_by, created_at, updated_by, updated_at)
|
|
23
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
24
|
+
`;
|
|
25
|
+
await this.pool.query(sql, [
|
|
26
|
+
record.id,
|
|
27
|
+
record.userId,
|
|
28
|
+
record.agentCode,
|
|
29
|
+
record.type,
|
|
30
|
+
record.content,
|
|
31
|
+
record.relevanceScore,
|
|
32
|
+
record.createdBy || 'system',
|
|
33
|
+
record.createdAt,
|
|
34
|
+
record.updatedBy || 'system',
|
|
35
|
+
record.updatedAt,
|
|
36
|
+
]);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* SELECT memories by user_id and agent_id
|
|
40
|
+
* Excludes soft-deleted records
|
|
41
|
+
*/
|
|
42
|
+
async findByUserAndAgent(userId, agentCode, limit) {
|
|
43
|
+
const sql = limit !== undefined
|
|
44
|
+
? `SELECT * FROM memories WHERE user_id = $1 AND agent_id = $2 AND is_deleted = FALSE ORDER BY relevance_score DESC LIMIT $3`
|
|
45
|
+
: `SELECT * FROM memories WHERE user_id = $1 AND agent_id = $2 AND is_deleted = FALSE ORDER BY relevance_score DESC`;
|
|
46
|
+
const params = limit !== undefined ? [userId, agentCode, limit] : [userId, agentCode];
|
|
47
|
+
const { rows } = await this.pool.query(sql, params);
|
|
48
|
+
return rows.map((row) => this.rowToRecord(row));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Soft delete memory (implements IMemoryRepository.delete)
|
|
52
|
+
*/
|
|
53
|
+
async delete(id) {
|
|
54
|
+
await this.softDelete(id, 'system');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Soft delete memory with audit
|
|
58
|
+
*/
|
|
59
|
+
async softDelete(id, deletedBy) {
|
|
60
|
+
const sql = `
|
|
61
|
+
UPDATE memories
|
|
62
|
+
SET is_deleted = TRUE, deleted_by = $1, deleted_at = NOW()
|
|
63
|
+
WHERE id = $2 AND is_deleted = FALSE
|
|
64
|
+
`;
|
|
65
|
+
await this.pool.query(sql, [deletedBy, id]);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* UPDATE memory record
|
|
69
|
+
*/
|
|
70
|
+
async update(record) {
|
|
71
|
+
const sql = `
|
|
72
|
+
UPDATE memories
|
|
73
|
+
SET content = $1, relevance_score = $2, type = $3, updated_by = $4, updated_at = $5
|
|
74
|
+
WHERE id = $6 AND is_deleted = FALSE
|
|
75
|
+
`;
|
|
76
|
+
await this.pool.query(sql, [
|
|
77
|
+
record.content,
|
|
78
|
+
record.relevanceScore,
|
|
79
|
+
record.type,
|
|
80
|
+
record.updatedBy || 'system',
|
|
81
|
+
record.updatedAt,
|
|
82
|
+
record.id,
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
85
|
+
// ─────────────────────────────────────────────
|
|
86
|
+
// Private Helpers
|
|
87
|
+
// ─────────────────────────────────────────────
|
|
88
|
+
/**
|
|
89
|
+
* 将 PostgreSQL 行数据转换为 MemoryRecord
|
|
90
|
+
*/
|
|
91
|
+
rowToRecord(row) {
|
|
92
|
+
return {
|
|
93
|
+
id: row.id,
|
|
94
|
+
userId: row.user_id,
|
|
95
|
+
agentCode: row.agent_id,
|
|
96
|
+
type: row.type,
|
|
97
|
+
content: row.content,
|
|
98
|
+
relevanceScore: row.relevance_score,
|
|
99
|
+
createdBy: row.created_by,
|
|
100
|
+
createdAt: row.created_at.toISOString(),
|
|
101
|
+
updatedBy: row.updated_by,
|
|
102
|
+
updatedAt: row.updated_at.toISOString(),
|
|
103
|
+
isDeleted: row.is_deleted,
|
|
104
|
+
deletedBy: row.deleted_by,
|
|
105
|
+
deletedAt: row.deleted_at?.toISOString(),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SemanticRetrievalService — 语义检索服务
|
|
3
|
+
*
|
|
4
|
+
* 提供基于语义相似度的记忆检索能力。
|
|
5
|
+
* 支持多种检索策略:
|
|
6
|
+
* - 关键词匹配(简单)
|
|
7
|
+
* - 向量相似度(需外部向量数据库)
|
|
8
|
+
* - 混合检索(关键词 + 向量)
|
|
9
|
+
*
|
|
10
|
+
* @see long-term-memory.service.ts 记忆管理
|
|
11
|
+
* @see requirements.md Requirement 4.4
|
|
12
|
+
*/
|
|
13
|
+
import type { MemoryRecord } from './long-term-memory.service.js';
|
|
14
|
+
/**
|
|
15
|
+
* 检索策略类型
|
|
16
|
+
*/
|
|
17
|
+
export type RetrievalStrategy = 'keyword' | 'vector' | 'hybrid';
|
|
18
|
+
/**
|
|
19
|
+
* 检索配置
|
|
20
|
+
*/
|
|
21
|
+
export interface RetrievalConfig {
|
|
22
|
+
/** 检索策略(默认 keyword) */
|
|
23
|
+
strategy: RetrievalStrategy;
|
|
24
|
+
/** 返回结果数量上限(默认 10) */
|
|
25
|
+
limit: number;
|
|
26
|
+
/** 相似度阈值(默认 0.7,仅 vector/hybrid 策略) */
|
|
27
|
+
similarityThreshold: number;
|
|
28
|
+
/** 关键词权重(hybrid 策略,默认 0.3) */
|
|
29
|
+
keywordWeight: number;
|
|
30
|
+
/** 向量权重(hybrid 策略,默认 0.7) */
|
|
31
|
+
vectorWeight: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 默认检索配置
|
|
35
|
+
*/
|
|
36
|
+
export declare const DEFAULT_RETRIEVAL_CONFIG: RetrievalConfig;
|
|
37
|
+
/**
|
|
38
|
+
* 检索结果项
|
|
39
|
+
*/
|
|
40
|
+
export interface RetrievalResult {
|
|
41
|
+
/** 记忆记录 */
|
|
42
|
+
record: MemoryRecord;
|
|
43
|
+
/** 相似度分数(0-1) */
|
|
44
|
+
score: number;
|
|
45
|
+
/** 匹配的关键词(keyword 策略) */
|
|
46
|
+
matchedKeywords?: string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 向量存储接口
|
|
50
|
+
*
|
|
51
|
+
* 由外部注入,支持不同的向量数据库实现。
|
|
52
|
+
*/
|
|
53
|
+
export interface IVectorStore {
|
|
54
|
+
/**
|
|
55
|
+
* 存储向量
|
|
56
|
+
*
|
|
57
|
+
* @param id - 记录 ID
|
|
58
|
+
* @param vector - 向量
|
|
59
|
+
* @param metadata - 元数据
|
|
60
|
+
*/
|
|
61
|
+
upsert(id: string, vector: number[], metadata?: Record<string, unknown>): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* 查询相似向量
|
|
64
|
+
*
|
|
65
|
+
* @param queryVector - 查询向量
|
|
66
|
+
* @param limit - 返回数量
|
|
67
|
+
* @param threshold - 相似度阈值
|
|
68
|
+
* @returns 相似向量列表
|
|
69
|
+
*/
|
|
70
|
+
query(queryVector: number[], limit: number, threshold?: number): Promise<VectorResult[]>;
|
|
71
|
+
/**
|
|
72
|
+
* 删除向量
|
|
73
|
+
*
|
|
74
|
+
* @param id - 记录 ID
|
|
75
|
+
*/
|
|
76
|
+
delete(id: string): Promise<void>;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 向量查询结果
|
|
80
|
+
*/
|
|
81
|
+
export interface VectorResult {
|
|
82
|
+
/** 记录 ID */
|
|
83
|
+
id: string;
|
|
84
|
+
/** 相似度分数 */
|
|
85
|
+
score: number;
|
|
86
|
+
/** 元数据 */
|
|
87
|
+
metadata?: Record<string, unknown>;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Embedding 函数接口
|
|
91
|
+
*
|
|
92
|
+
* 将文本转换为向量。
|
|
93
|
+
*/
|
|
94
|
+
export type EmbeddingFunction = (text: string) => Promise<number[]>;
|
|
95
|
+
/**
|
|
96
|
+
* SemanticRetrievalService — 语义检索服务实现
|
|
97
|
+
*/
|
|
98
|
+
export declare class SemanticRetrievalService {
|
|
99
|
+
private readonly config;
|
|
100
|
+
private readonly vectorStore?;
|
|
101
|
+
private readonly embedding;
|
|
102
|
+
constructor(config?: Partial<RetrievalConfig>, vectorStore?: IVectorStore, embedding?: EmbeddingFunction);
|
|
103
|
+
/**
|
|
104
|
+
* 检索相关记忆
|
|
105
|
+
*
|
|
106
|
+
* @param query - 查询文本
|
|
107
|
+
* @param memories - 候选记忆列表
|
|
108
|
+
* @returns 检索结果
|
|
109
|
+
*/
|
|
110
|
+
retrieve(query: string, memories: MemoryRecord[]): Promise<RetrievalResult[]>;
|
|
111
|
+
/**
|
|
112
|
+
* 关键词检索
|
|
113
|
+
*
|
|
114
|
+
* 基于关键词匹配的简单检索。
|
|
115
|
+
*/
|
|
116
|
+
private keywordRetrieve;
|
|
117
|
+
/**
|
|
118
|
+
* 向量检索
|
|
119
|
+
*
|
|
120
|
+
* 基于向量相似度的检索。
|
|
121
|
+
*/
|
|
122
|
+
private vectorRetrieve;
|
|
123
|
+
/**
|
|
124
|
+
* 混合检索
|
|
125
|
+
*
|
|
126
|
+
* 结合关键词和向量的混合检索。
|
|
127
|
+
*/
|
|
128
|
+
private hybridRetrieve;
|
|
129
|
+
/**
|
|
130
|
+
* 提取关键词
|
|
131
|
+
*
|
|
132
|
+
* 简单的关键词提取(基于空格分割 + 停用词过滤)。
|
|
133
|
+
*/
|
|
134
|
+
private extractKeywords;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* InMemoryVectorStore — 内存向量存储(测试用)
|
|
138
|
+
*/
|
|
139
|
+
export declare class InMemoryVectorStore implements IVectorStore {
|
|
140
|
+
private readonly store;
|
|
141
|
+
upsert(id: string, vector: number[], metadata?: Record<string, unknown>): Promise<void>;
|
|
142
|
+
query(queryVector: number[], limit: number, threshold?: number): Promise<VectorResult[]>;
|
|
143
|
+
delete(id: string): Promise<void>;
|
|
144
|
+
/**
|
|
145
|
+
* 计算余弦相似度
|
|
146
|
+
*/
|
|
147
|
+
private cosineSimilarity;
|
|
148
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SemanticRetrievalService — 语义检索服务
|
|
3
|
+
*
|
|
4
|
+
* 提供基于语义相似度的记忆检索能力。
|
|
5
|
+
* 支持多种检索策略:
|
|
6
|
+
* - 关键词匹配(简单)
|
|
7
|
+
* - 向量相似度(需外部向量数据库)
|
|
8
|
+
* - 混合检索(关键词 + 向量)
|
|
9
|
+
*
|
|
10
|
+
* @see long-term-memory.service.ts 记忆管理
|
|
11
|
+
* @see requirements.md Requirement 4.4
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* 默认检索配置
|
|
15
|
+
*/
|
|
16
|
+
export const DEFAULT_RETRIEVAL_CONFIG = {
|
|
17
|
+
strategy: 'keyword',
|
|
18
|
+
limit: 10,
|
|
19
|
+
similarityThreshold: 0.7,
|
|
20
|
+
keywordWeight: 0.3,
|
|
21
|
+
vectorWeight: 0.7,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* 默认 Embedding 函数(占位)
|
|
25
|
+
*
|
|
26
|
+
* 实际使用时应注入真实的 Embedding 函数(如 OpenAI Embedding)。
|
|
27
|
+
*/
|
|
28
|
+
async function defaultEmbedding(text) {
|
|
29
|
+
// 简单的哈希向量(占位,实际应使用真实的 Embedding 模型)
|
|
30
|
+
const vector = new Array(128).fill(0);
|
|
31
|
+
for (let i = 0; i < text.length; i++) {
|
|
32
|
+
vector[i % 128] += text.charCodeAt(i) / 1000;
|
|
33
|
+
}
|
|
34
|
+
// 归一化
|
|
35
|
+
const norm = Math.sqrt(vector.reduce((sum, v) => sum + v * v, 0));
|
|
36
|
+
return vector.map((v) => v / norm);
|
|
37
|
+
}
|
|
38
|
+
// ─────────────────────────────────────────────
|
|
39
|
+
// 语义检索服务
|
|
40
|
+
// ─────────────────────────────────────────────
|
|
41
|
+
/**
|
|
42
|
+
* SemanticRetrievalService — 语义检索服务实现
|
|
43
|
+
*/
|
|
44
|
+
export class SemanticRetrievalService {
|
|
45
|
+
config;
|
|
46
|
+
vectorStore;
|
|
47
|
+
embedding;
|
|
48
|
+
constructor(config, vectorStore, embedding) {
|
|
49
|
+
this.config = { ...DEFAULT_RETRIEVAL_CONFIG, ...config };
|
|
50
|
+
this.vectorStore = vectorStore;
|
|
51
|
+
this.embedding = embedding ?? defaultEmbedding;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 检索相关记忆
|
|
55
|
+
*
|
|
56
|
+
* @param query - 查询文本
|
|
57
|
+
* @param memories - 候选记忆列表
|
|
58
|
+
* @returns 检索结果
|
|
59
|
+
*/
|
|
60
|
+
async retrieve(query, memories) {
|
|
61
|
+
switch (this.config.strategy) {
|
|
62
|
+
case 'keyword':
|
|
63
|
+
return this.keywordRetrieve(query, memories);
|
|
64
|
+
case 'vector':
|
|
65
|
+
return this.vectorRetrieve(query, memories);
|
|
66
|
+
case 'hybrid':
|
|
67
|
+
return this.hybridRetrieve(query, memories);
|
|
68
|
+
default:
|
|
69
|
+
return this.keywordRetrieve(query, memories);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 关键词检索
|
|
74
|
+
*
|
|
75
|
+
* 基于关键词匹配的简单检索。
|
|
76
|
+
*/
|
|
77
|
+
async keywordRetrieve(query, memories) {
|
|
78
|
+
const keywords = this.extractKeywords(query);
|
|
79
|
+
const results = [];
|
|
80
|
+
for (const memory of memories) {
|
|
81
|
+
const content = memory.content.toLowerCase();
|
|
82
|
+
const matchedKeywords = [];
|
|
83
|
+
let matchCount = 0;
|
|
84
|
+
for (const keyword of keywords) {
|
|
85
|
+
if (content.includes(keyword.toLowerCase())) {
|
|
86
|
+
matchedKeywords.push(keyword);
|
|
87
|
+
matchCount++;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (matchCount > 0) {
|
|
91
|
+
const score = matchCount / keywords.length;
|
|
92
|
+
results.push({
|
|
93
|
+
record: memory,
|
|
94
|
+
score,
|
|
95
|
+
matchedKeywords,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// 按分数降序排序
|
|
100
|
+
results.sort((a, b) => b.score - a.score);
|
|
101
|
+
return results.slice(0, this.config.limit);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 向量检索
|
|
105
|
+
*
|
|
106
|
+
* 基于向量相似度的检索。
|
|
107
|
+
*/
|
|
108
|
+
async vectorRetrieve(query, memories) {
|
|
109
|
+
if (!this.vectorStore) {
|
|
110
|
+
// 如果没有向量存储,回退到关键词检索
|
|
111
|
+
return this.keywordRetrieve(query, memories);
|
|
112
|
+
}
|
|
113
|
+
// 生成查询向量
|
|
114
|
+
const queryVector = await this.embedding(query);
|
|
115
|
+
// 查询相似向量
|
|
116
|
+
const vectorResults = await this.vectorStore.query(queryVector, this.config.limit, this.config.similarityThreshold);
|
|
117
|
+
// 映射到记忆记录
|
|
118
|
+
const results = [];
|
|
119
|
+
for (const vectorResult of vectorResults) {
|
|
120
|
+
const memory = memories.find((m) => m.id === vectorResult.id);
|
|
121
|
+
if (memory) {
|
|
122
|
+
results.push({
|
|
123
|
+
record: memory,
|
|
124
|
+
score: vectorResult.score,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return results;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* 混合检索
|
|
132
|
+
*
|
|
133
|
+
* 结合关键词和向量的混合检索。
|
|
134
|
+
*/
|
|
135
|
+
async hybridRetrieve(query, memories) {
|
|
136
|
+
// 关键词检索结果
|
|
137
|
+
const keywordResults = await this.keywordRetrieve(query, memories);
|
|
138
|
+
// 向量检索结果
|
|
139
|
+
const vectorResults = await this.vectorRetrieve(query, memories);
|
|
140
|
+
// 合并结果
|
|
141
|
+
const mergedResults = new Map();
|
|
142
|
+
// 添加关键词结果
|
|
143
|
+
for (const result of keywordResults) {
|
|
144
|
+
mergedResults.set(result.record.id, {
|
|
145
|
+
...result,
|
|
146
|
+
score: result.score * this.config.keywordWeight,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// 添加/合并向量结果
|
|
150
|
+
for (const result of vectorResults) {
|
|
151
|
+
const existing = mergedResults.get(result.record.id);
|
|
152
|
+
if (existing) {
|
|
153
|
+
// 合并分数
|
|
154
|
+
existing.score += result.score * this.config.vectorWeight;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
mergedResults.set(result.record.id, {
|
|
158
|
+
...result,
|
|
159
|
+
score: result.score * this.config.vectorWeight,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// 转换为数组并排序
|
|
164
|
+
const results = Array.from(mergedResults.values());
|
|
165
|
+
results.sort((a, b) => b.score - a.score);
|
|
166
|
+
return results.slice(0, this.config.limit);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* 提取关键词
|
|
170
|
+
*
|
|
171
|
+
* 简单的关键词提取(基于空格分割 + 停用词过滤)。
|
|
172
|
+
*/
|
|
173
|
+
extractKeywords(text) {
|
|
174
|
+
// 停用词列表
|
|
175
|
+
const stopWords = new Set([
|
|
176
|
+
'的', '了', '是', '在', '我', '有', '和', '就', '不', '人', '都', '一', '一个',
|
|
177
|
+
'上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好',
|
|
178
|
+
'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
179
|
+
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
|
|
180
|
+
'should', 'may', 'might', 'can', 'shall', 'to', 'of', 'in', 'for',
|
|
181
|
+
'on', 'with', 'at', 'by', 'from', 'as', 'into', 'through', 'during',
|
|
182
|
+
'before', 'after', 'above', 'below', 'between', 'out', 'off', 'over',
|
|
183
|
+
'under', 'again', 'further', 'then', 'once',
|
|
184
|
+
]);
|
|
185
|
+
// 分词(简单按空格和标点分割)
|
|
186
|
+
const words = text
|
|
187
|
+
.toLowerCase()
|
|
188
|
+
.replace(/[^\w\u4e00-\u9fff]/g, ' ')
|
|
189
|
+
.split(/\s+/)
|
|
190
|
+
.filter((word) => word.length > 1 && !stopWords.has(word));
|
|
191
|
+
return [...new Set(words)];
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// ─────────────────────────────────────────────
|
|
195
|
+
// In-Memory 向量存储(测试用)
|
|
196
|
+
// ─────────────────────────────────────────────
|
|
197
|
+
/**
|
|
198
|
+
* InMemoryVectorStore — 内存向量存储(测试用)
|
|
199
|
+
*/
|
|
200
|
+
export class InMemoryVectorStore {
|
|
201
|
+
store = new Map();
|
|
202
|
+
async upsert(id, vector, metadata) {
|
|
203
|
+
this.store.set(id, { vector, metadata });
|
|
204
|
+
}
|
|
205
|
+
async query(queryVector, limit, threshold) {
|
|
206
|
+
const results = [];
|
|
207
|
+
for (const [id, { vector }] of this.store) {
|
|
208
|
+
const score = this.cosineSimilarity(queryVector, vector);
|
|
209
|
+
if (!threshold || score >= threshold) {
|
|
210
|
+
results.push({ id, score });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// 按分数降序排序
|
|
214
|
+
results.sort((a, b) => b.score - a.score);
|
|
215
|
+
return results.slice(0, limit);
|
|
216
|
+
}
|
|
217
|
+
async delete(id) {
|
|
218
|
+
this.store.delete(id);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* 计算余弦相似度
|
|
222
|
+
*/
|
|
223
|
+
cosineSimilarity(a, b) {
|
|
224
|
+
if (a.length !== b.length)
|
|
225
|
+
return 0;
|
|
226
|
+
let dotProduct = 0;
|
|
227
|
+
let normA = 0;
|
|
228
|
+
let normB = 0;
|
|
229
|
+
for (let i = 0; i < a.length; i++) {
|
|
230
|
+
dotProduct += a[i] * b[i];
|
|
231
|
+
normA += a[i] * a[i];
|
|
232
|
+
normB += b[i] * b[i];
|
|
233
|
+
}
|
|
234
|
+
if (normA === 0 || normB === 0)
|
|
235
|
+
return 0;
|
|
236
|
+
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Echo LLM Provider — 开发/测试用,将用户最后一条消息回显为 assistant 回复
|
|
3
|
+
*/
|
|
4
|
+
import type { GraphMessage } from '../graph/contracts/executable-graph.js';
|
|
5
|
+
import type { ILLMProvider, LLMNodeConfig, LLMResponse, LLMChunk } from '../graph/nodes/llm-node.js';
|
|
6
|
+
export declare class EchoLLMProvider implements ILLMProvider {
|
|
7
|
+
invoke(messages: GraphMessage[], config: LLMNodeConfig): Promise<LLMResponse>;
|
|
8
|
+
stream(messages: GraphMessage[], config: LLMNodeConfig): AsyncIterableIterator<LLMChunk>;
|
|
9
|
+
}
|
|
10
|
+
export declare function createDefaultLLMProvider(): ILLMProvider;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Echo LLM Provider — 开发/测试用,将用户最后一条消息回显为 assistant 回复
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 解析 `call:<toolName> [args-json | 任意字符串]` 触发语法:
|
|
6
|
+
* - `call:echo-tool` → `{ name: 'echo-tool', arguments: {} }`
|
|
7
|
+
* - `call:echo-tool {"text":"hi"}` → arguments 使用解析后的 JSON
|
|
8
|
+
* - `call:echo-tool hi` → arguments 兜底为 `{ text: 'hi' }`
|
|
9
|
+
*
|
|
10
|
+
* 仅用于本地闭环 (`EAP_TOOL_EXECUTION_MODE=mock`) 下驱动 ToolNode,
|
|
11
|
+
* 让开发者无需接入真实 LLM 即可完成 tool 调用链路验证。
|
|
12
|
+
*/
|
|
13
|
+
function parseSyntheticToolCall(content) {
|
|
14
|
+
if (!content)
|
|
15
|
+
return null;
|
|
16
|
+
const match = content.match(/^\s*call:([^\s]+)\s*(.*)$/);
|
|
17
|
+
if (!match)
|
|
18
|
+
return null;
|
|
19
|
+
const [, name, tail] = match;
|
|
20
|
+
const trimmed = tail?.trim() ?? '';
|
|
21
|
+
let args = {};
|
|
22
|
+
if (trimmed) {
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(trimmed);
|
|
25
|
+
args = typeof parsed === 'object' && parsed !== null ? parsed : { text: trimmed };
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
args = { text: trimmed };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
id: `call-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
33
|
+
name,
|
|
34
|
+
arguments: args,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export class EchoLLMProvider {
|
|
38
|
+
async invoke(messages, config) {
|
|
39
|
+
const lastUser = [...messages].reverse().find((m) => m.role === 'user');
|
|
40
|
+
const syntheticToolCall = parseSyntheticToolCall(lastUser?.content);
|
|
41
|
+
const content = syntheticToolCall
|
|
42
|
+
? `[echo:${config.model ?? 'default'}] dispatching tool ${syntheticToolCall.name}`
|
|
43
|
+
: lastUser?.content
|
|
44
|
+
? `[echo:${config.model ?? 'default'}] ${lastUser.content}`
|
|
45
|
+
: '[echo] Hello from EAP runtime';
|
|
46
|
+
const inputText = messages.map((m) => m.content).join(' ');
|
|
47
|
+
const inputTokens = Math.ceil(inputText.length / 4);
|
|
48
|
+
const outputTokens = Math.ceil(content.length / 4);
|
|
49
|
+
return {
|
|
50
|
+
content,
|
|
51
|
+
toolCalls: syntheticToolCall ? [syntheticToolCall] : undefined,
|
|
52
|
+
inputTokens,
|
|
53
|
+
outputTokens,
|
|
54
|
+
model: config.model ?? 'echo',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async *stream(messages, config) {
|
|
58
|
+
const response = await this.invoke(messages, config);
|
|
59
|
+
const words = response.content.split(' ');
|
|
60
|
+
for (let i = 0; i < words.length; i++) {
|
|
61
|
+
const isEnd = i === words.length - 1;
|
|
62
|
+
yield {
|
|
63
|
+
content: (i === 0 ? '' : ' ') + words[i],
|
|
64
|
+
isEnd,
|
|
65
|
+
inputTokens: isEnd ? response.inputTokens : undefined,
|
|
66
|
+
outputTokens: isEnd ? response.outputTokens : undefined,
|
|
67
|
+
toolCalls: isEnd ? response.toolCalls : undefined,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 根据环境变量创建 LLM Provider
|
|
74
|
+
* - OPENAI_API_KEY 存在 → HttpLLMProvider
|
|
75
|
+
* - 否则 → EchoLLMProvider
|
|
76
|
+
*/
|
|
77
|
+
import { HttpLLMProvider } from './http-llm-provider.js';
|
|
78
|
+
export function createDefaultLLMProvider() {
|
|
79
|
+
if (process.env.OPENAI_API_KEY) {
|
|
80
|
+
return new HttpLLMProvider({
|
|
81
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
82
|
+
baseUrl: process.env.OPENAI_BASE_URL ?? 'https://api.openai.com/v1',
|
|
83
|
+
defaultModel: process.env.EAP_DEFAULT_MODEL ?? 'DeepSeek-V4-Pro',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return new EchoLLMProvider();
|
|
87
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP LLM Provider — OpenAI 兼容 API
|
|
3
|
+
*
|
|
4
|
+
* 支持:
|
|
5
|
+
* - 真流式输出(stream: true + SSE chunk 解析)
|
|
6
|
+
* - function calling(tools / tool_choice 参数)
|
|
7
|
+
* - tool_calls 解析(同步 & 流式)
|
|
8
|
+
*/
|
|
9
|
+
import type { GraphMessage } from '../graph/contracts/executable-graph.js';
|
|
10
|
+
import type { ILLMProvider, LLMNodeConfig, LLMResponse, LLMChunk } from '../graph/nodes/llm-node.js';
|
|
11
|
+
export interface HttpLLMProviderConfig {
|
|
12
|
+
apiKey: string;
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
defaultModel?: string;
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class HttpLLMProvider implements ILLMProvider {
|
|
18
|
+
private readonly apiKey;
|
|
19
|
+
private readonly baseUrl;
|
|
20
|
+
private readonly defaultModel;
|
|
21
|
+
private readonly timeoutMs;
|
|
22
|
+
constructor(config: HttpLLMProviderConfig);
|
|
23
|
+
invoke(messages: GraphMessage[], config: LLMNodeConfig): Promise<LLMResponse>;
|
|
24
|
+
stream(messages: GraphMessage[], config: LLMNodeConfig): AsyncIterableIterator<LLMChunk>;
|
|
25
|
+
private buildRequestBody;
|
|
26
|
+
/**
|
|
27
|
+
* 解析同步响应中的 tool_calls
|
|
28
|
+
*/
|
|
29
|
+
private parseToolCalls;
|
|
30
|
+
/**
|
|
31
|
+
* 将流式累积的 tool_calls 转换为最终结果
|
|
32
|
+
*/
|
|
33
|
+
private finalizeToolCalls;
|
|
34
|
+
private formatNetworkError;
|
|
35
|
+
}
|