@inobeta/api 0.9.0 → 0.10.0

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.
@@ -0,0 +1,36 @@
1
+ import type { Knex } from "knex";
2
+ import type { AiModelDriver, AgentResult, ValidatedSuggestion } from "./ai-agent.types";
3
+ export declare abstract class AiAgent<TInput, TSuggestion> {
4
+ protected readonly knex: Knex;
5
+ protected readonly agentCode: string;
6
+ constructor(knex: Knex, agentCode: string);
7
+ run(input: TInput, userId: number, driver: AiModelDriver): Promise<AgentResult<TSuggestion>>;
8
+ protected abstract gatherContext(input: TInput): Promise<unknown>;
9
+ protected abstract buildPrompt(context: unknown): string;
10
+ protected abstract parseSuggestions(rawContent: string): Array<{
11
+ data: TSuggestion;
12
+ confidence: number;
13
+ reason: string;
14
+ }>;
15
+ protected abstract validateSuggestions(suggestions: Array<{
16
+ data: TSuggestion;
17
+ confidence: number;
18
+ reason: string;
19
+ }>, context: unknown): Promise<Array<{
20
+ data: TSuggestion;
21
+ confidence: number;
22
+ reason: string;
23
+ }>>;
24
+ protected getModelOptions(): {
25
+ systemPrompt?: string;
26
+ temperature?: number;
27
+ maxTokens?: number;
28
+ };
29
+ protected buildInputSummary(_input: TInput): Record<string, unknown> | null;
30
+ protected buildOutputSummary(_suggestions: ValidatedSuggestion<TSuggestion>[]): Record<string, unknown> | null;
31
+ private resolveAgent;
32
+ private createExecution;
33
+ private completeExecution;
34
+ private failExecution;
35
+ }
36
+ //# sourceMappingURL=ai-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-agent.d.ts","sourceRoot":"","sources":["../../src/ai-agent/ai-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,KAAK,EACR,aAAa,EACb,WAAW,EACX,mBAAmB,EAGtB,MAAM,kBAAkB,CAAC;AAE1B,8BAAsB,OAAO,CAAC,MAAM,EAAE,WAAW;IAEzC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI;IAC7B,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM;gBADjB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,MAAM;IAGlC,GAAG,CACL,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,aAAa,GACtB,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;IAuCpC,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAEjE,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAExD,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,CAAC;QAC3D,IAAI,EAAE,WAAW,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAClB,CAAC;IAEF,SAAS,CAAC,QAAQ,CAAC,mBAAmB,CAClC,WAAW,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,WAAW,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAClB,CAAC,EACF,OAAO,EAAE,OAAO,GACjB,OAAO,CACN,KAAK,CAAC;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CACnE;IAID,SAAS,CAAC,eAAe,IAAI;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;IAIhG,SAAS,CAAC,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3E,SAAS,CAAC,kBAAkB,CACxB,YAAY,EAAE,mBAAmB,CAAC,WAAW,CAAC,EAAE,GACjD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;YAMnB,YAAY;YAcZ,eAAe;YAuBf,iBAAiB;YAmDjB,aAAa;CAiB9B"}
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AiAgent = void 0;
4
+ class AiAgent {
5
+ knex;
6
+ agentCode;
7
+ constructor(knex, agentCode) {
8
+ this.knex = knex;
9
+ this.agentCode = agentCode;
10
+ }
11
+ async run(input, userId, driver) {
12
+ const agent = await this.resolveAgent();
13
+ const executionId = await this.createExecution(agent.id, userId, driver, input);
14
+ const startTime = Date.now();
15
+ try {
16
+ const context = await this.gatherContext(input);
17
+ const prompt = this.buildPrompt(context);
18
+ const modelResponse = await driver.complete(prompt, this.getModelOptions());
19
+ const durationMs = Date.now() - startTime;
20
+ const parsed = this.parseSuggestions(modelResponse.content);
21
+ const validated = await this.validateSuggestions(parsed, context);
22
+ const suggestions = await this.completeExecution(executionId, durationMs, validated, modelResponse, input);
23
+ return { executionId, suggestions, durationMs };
24
+ }
25
+ catch (error) {
26
+ const durationMs = Date.now() - startTime;
27
+ await this.failExecution(executionId, durationMs, error);
28
+ throw error;
29
+ }
30
+ }
31
+ // ---- Overridable hooks ----
32
+ getModelOptions() {
33
+ return {};
34
+ }
35
+ buildInputSummary(_input) {
36
+ return null;
37
+ }
38
+ buildOutputSummary(_suggestions) {
39
+ return null;
40
+ }
41
+ // ---- Private framework methods ----
42
+ async resolveAgent() {
43
+ const agent = await this.knex("ai_agents")
44
+ .where({ code: this.agentCode, is_active: true })
45
+ .first();
46
+ if (!agent) {
47
+ throw new Error(`AI agent "${this.agentCode}" not found or inactive`);
48
+ }
49
+ return agent;
50
+ }
51
+ async createExecution(agentId, userId, driver, input) {
52
+ const [row] = await this.knex("ai_agent_executions")
53
+ .insert({
54
+ agent_id: agentId,
55
+ user_id: userId,
56
+ driver: driver.getDriverName(),
57
+ model: "",
58
+ started_at: new Date(),
59
+ status: "running",
60
+ input_summary: JSON.stringify(this.buildInputSummary(input)),
61
+ })
62
+ .returning("id");
63
+ return row.id;
64
+ }
65
+ async completeExecution(executionId, durationMs, validated, modelResponse, input) {
66
+ const suggestionRows = validated.map((s) => ({
67
+ execution_id: executionId,
68
+ suggestion_data: JSON.stringify(s.data),
69
+ confidence: s.confidence,
70
+ reason: s.reason,
71
+ status: "pending",
72
+ }));
73
+ let insertedIds = [];
74
+ if (suggestionRows.length > 0) {
75
+ insertedIds = await this.knex("ai_agent_suggestions")
76
+ .insert(suggestionRows)
77
+ .returning("id");
78
+ }
79
+ const suggestions = validated.map((s, i) => ({
80
+ suggestionId: insertedIds[i]?.id ?? 0,
81
+ data: s.data,
82
+ confidence: s.confidence,
83
+ reason: s.reason,
84
+ }));
85
+ const outputSummary = this.buildOutputSummary(suggestions);
86
+ await this.knex("ai_agent_executions")
87
+ .where({ id: executionId })
88
+ .update({
89
+ completed_at: new Date(),
90
+ duration_ms: durationMs,
91
+ status: "completed",
92
+ model: modelResponse.model,
93
+ input_tokens: modelResponse.inputTokens,
94
+ output_tokens: modelResponse.outputTokens,
95
+ output_summary: JSON.stringify(outputSummary),
96
+ });
97
+ return suggestions;
98
+ }
99
+ async failExecution(executionId, durationMs, error) {
100
+ const message = error instanceof Error ? error.message : String(error);
101
+ await this.knex("ai_agent_executions")
102
+ .where({ id: executionId })
103
+ .update({
104
+ completed_at: new Date(),
105
+ duration_ms: durationMs,
106
+ status: "failed",
107
+ error_message: message,
108
+ });
109
+ }
110
+ }
111
+ exports.AiAgent = AiAgent;
112
+ //# sourceMappingURL=ai-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-agent.js","sourceRoot":"","sources":["../../src/ai-agent/ai-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ export interface ModelOptions {
2
+ maxTokens?: number;
3
+ temperature?: number;
4
+ systemPrompt?: string;
5
+ }
6
+ export interface ModelResponse {
7
+ content: string;
8
+ inputTokens: number;
9
+ outputTokens: number;
10
+ model: string;
11
+ }
12
+ export interface AiModelDriver {
13
+ complete(prompt: string, options?: ModelOptions): Promise<ModelResponse>;
14
+ getDriverName(): string;
15
+ }
16
+ export interface AgentResult<TSuggestion> {
17
+ executionId: number;
18
+ suggestions: ValidatedSuggestion<TSuggestion>[];
19
+ durationMs: number;
20
+ }
21
+ export interface ValidatedSuggestion<TSuggestion> {
22
+ suggestionId: number;
23
+ data: TSuggestion;
24
+ confidence: number;
25
+ reason: string;
26
+ }
27
+ export interface AiAgentRow {
28
+ id: number;
29
+ code: string;
30
+ description: string | null;
31
+ is_active: boolean;
32
+ created_at: string;
33
+ }
34
+ export interface AiAgentExecutionRow {
35
+ id: number;
36
+ agent_id: number;
37
+ user_id: number | null;
38
+ driver: string;
39
+ model: string;
40
+ started_at: string;
41
+ completed_at: string | null;
42
+ duration_ms: number | null;
43
+ status: "running" | "completed" | "failed";
44
+ error_message: string | null;
45
+ input_summary: Record<string, unknown> | null;
46
+ output_summary: Record<string, unknown> | null;
47
+ input_tokens: number | null;
48
+ output_tokens: number | null;
49
+ created_at: string;
50
+ }
51
+ export interface AiAgentSuggestionRow {
52
+ id: number;
53
+ execution_id: number;
54
+ suggestion_data: Record<string, unknown>;
55
+ confidence: number | null;
56
+ reason: string | null;
57
+ status: "pending" | "accepted" | "rejected";
58
+ reviewed_at: string | null;
59
+ created_at: string;
60
+ }
61
+ //# sourceMappingURL=ai-agent.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-agent.types.d.ts","sourceRoot":"","sources":["../../src/ai-agent/ai-agent.types.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,YAAY;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACzE,aAAa,IAAI,MAAM,CAAC;CAC3B;AAMD,MAAM,WAAW,WAAW,CAAC,WAAW;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,mBAAmB,CAAC,WAAW,CAAC,EAAE,CAAC;IAChD,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB,CAAC,WAAW;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,WAAW,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAClB;AAMD,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC3C,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC9C,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC/C,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;IAC5C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACtB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=ai-agent.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-agent.types.js","sourceRoot":"","sources":["../../src/ai-agent/ai-agent.types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,16 @@
1
+ export interface DriverModelInfo {
2
+ driverName: string;
3
+ driverLabel: string;
4
+ models: ModelInfo[];
5
+ }
6
+ export interface ModelInfo {
7
+ id: string;
8
+ label: string;
9
+ isDefault: boolean;
10
+ }
11
+ export declare function getAvailableDrivers(): DriverModelInfo[];
12
+ export declare function getAvailableModels(driverName: string): ModelInfo[];
13
+ export declare function getDefaultModel(driverName: string): string | null;
14
+ export declare function isValidDriver(driverName: string): boolean;
15
+ export declare function isValidModel(driverName: string, modelId: string): boolean;
16
+ //# sourceMappingURL=driver.registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver.registry.d.ts","sourceRoot":"","sources":["../../src/ai-agent/driver.registry.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,SAAS,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;CACtB;AAgBD,wBAAgB,mBAAmB,IAAI,eAAe,EAAE,CAEvD;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,CAKlE;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIjE;AAED,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,YAAY,CACxB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GAChB,OAAO,CAET"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isValidModel = exports.isValidDriver = exports.getDefaultModel = exports.getAvailableModels = exports.getAvailableDrivers = void 0;
4
+ const DRIVER_REGISTRY = [
5
+ {
6
+ driverName: "claude",
7
+ driverLabel: "Anthropic Claude",
8
+ models: [
9
+ {
10
+ id: "claude-sonnet-4-20250514",
11
+ label: "Claude Sonnet 4",
12
+ isDefault: true,
13
+ },
14
+ ],
15
+ },
16
+ ];
17
+ function getAvailableDrivers() {
18
+ return DRIVER_REGISTRY;
19
+ }
20
+ exports.getAvailableDrivers = getAvailableDrivers;
21
+ function getAvailableModels(driverName) {
22
+ const driver = DRIVER_REGISTRY.find((d) => d.driverName === driverName);
23
+ return driver?.models ?? [];
24
+ }
25
+ exports.getAvailableModels = getAvailableModels;
26
+ function getDefaultModel(driverName) {
27
+ const models = getAvailableModels(driverName);
28
+ const defaultModel = models.find((m) => m.isDefault);
29
+ return defaultModel?.id ?? models[0]?.id ?? null;
30
+ }
31
+ exports.getDefaultModel = getDefaultModel;
32
+ function isValidDriver(driverName) {
33
+ return DRIVER_REGISTRY.some((d) => d.driverName === driverName);
34
+ }
35
+ exports.isValidDriver = isValidDriver;
36
+ function isValidModel(driverName, modelId) {
37
+ return getAvailableModels(driverName).some((m) => m.id === modelId);
38
+ }
39
+ exports.isValidModel = isValidModel;
40
+ //# sourceMappingURL=driver.registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver.registry.js","sourceRoot":"","sources":["../../src/ai-agent/driver.registry.ts"],"names":[],"mappings":";;;AAYA,MAAM,eAAe,GAAsB;IACvC;QACI,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,kBAAkB;QAC/B,MAAM,EAAE;YACJ;gBACI,EAAE,EAAE,0BAA0B;gBAC9B,KAAK,EAAE,iBAAiB;gBACxB,SAAS,EAAE,IAAI;aAClB;SACJ;KACJ;CACJ,CAAC;AAEF,SAAgB,mBAAmB;IAC/B,OAAO,eAAe,CAAC;AAC3B,CAAC;AAFD,kDAEC;AAED,SAAgB,kBAAkB,CAAC,UAAkB;IACjD,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAC/B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CACrC,CAAC;IACF,OAAO,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC;AAChC,CAAC;AALD,gDAKC;AAED,SAAgB,eAAe,CAAC,UAAkB;IAC9C,MAAM,MAAM,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACrD,OAAO,YAAY,EAAE,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC;AACrD,CAAC;AAJD,0CAIC;AAED,SAAgB,aAAa,CAAC,UAAkB;IAC5C,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;AACpE,CAAC;AAFD,sCAEC;AAED,SAAgB,YAAY,CACxB,UAAkB,EAClB,OAAe;IAEf,OAAO,kBAAkB,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;AACxE,CAAC;AALD,oCAKC"}
@@ -0,0 +1,15 @@
1
+ import type { AiModelDriver, ModelOptions, ModelResponse } from "../ai-agent.types";
2
+ export interface ClaudeDriverOptions {
3
+ apiKey: string;
4
+ defaultModel?: string;
5
+ baseUrl?: string;
6
+ }
7
+ export declare class ClaudeDriver implements AiModelDriver {
8
+ private readonly apiKey;
9
+ private readonly defaultModel;
10
+ private readonly baseUrl;
11
+ constructor(options: ClaudeDriverOptions);
12
+ complete(prompt: string, options?: ModelOptions): Promise<ModelResponse>;
13
+ getDriverName(): string;
14
+ }
15
+ //# sourceMappingURL=claude.driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.driver.d.ts","sourceRoot":"","sources":["../../../src/ai-agent/drivers/claude.driver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,aAAa,EACb,YAAY,EACZ,aAAa,EAChB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,mBAAmB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAWD,qBAAa,YAAa,YAAW,aAAa;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,mBAAmB;IAOlC,QAAQ,CACV,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,YAAY,GACvB,OAAO,CAAC,aAAa,CAAC;IA+CzB,aAAa,IAAI,MAAM;CAG1B"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClaudeDriver = void 0;
4
+ class ClaudeDriver {
5
+ apiKey;
6
+ defaultModel;
7
+ baseUrl;
8
+ constructor(options) {
9
+ this.apiKey = options.apiKey;
10
+ this.defaultModel = options.defaultModel ?? "claude-sonnet-4-20250514";
11
+ this.baseUrl =
12
+ options.baseUrl ?? "https://api.anthropic.com";
13
+ }
14
+ async complete(prompt, options) {
15
+ const body = {
16
+ model: this.defaultModel,
17
+ max_tokens: options?.maxTokens ?? 4096,
18
+ messages: [{ role: "user", content: prompt }],
19
+ };
20
+ if (options?.systemPrompt) {
21
+ body.system = options.systemPrompt;
22
+ }
23
+ if (options?.temperature !== undefined) {
24
+ body.temperature = options.temperature;
25
+ }
26
+ const response = await fetch(`${this.baseUrl}/v1/messages`, {
27
+ method: "POST",
28
+ headers: {
29
+ "Content-Type": "application/json",
30
+ "x-api-key": this.apiKey,
31
+ "anthropic-version": "2023-06-01",
32
+ },
33
+ body: JSON.stringify(body),
34
+ });
35
+ if (!response.ok) {
36
+ const errorText = await response.text();
37
+ throw new Error(`Claude API error (${response.status}): ${errorText}`);
38
+ }
39
+ const data = (await response.json());
40
+ const content = data.content
41
+ .filter((block) => block.type === "text")
42
+ .map((block) => block.text ?? "")
43
+ .join("\n");
44
+ return {
45
+ content,
46
+ inputTokens: data.usage.input_tokens,
47
+ outputTokens: data.usage.output_tokens,
48
+ model: data.model,
49
+ };
50
+ }
51
+ getDriverName() {
52
+ return "claude";
53
+ }
54
+ }
55
+ exports.ClaudeDriver = ClaudeDriver;
56
+ //# sourceMappingURL=claude.driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.driver.js","sourceRoot":"","sources":["../../../src/ai-agent/drivers/claude.driver.ts"],"names":[],"mappings":";;;AAqBA,MAAa,YAAY;IACJ,MAAM,CAAS;IACf,YAAY,CAAS;IACrB,OAAO,CAAS;IAEjC,YAAY,OAA4B;QACpC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,0BAA0B,CAAC;QACvE,IAAI,CAAC,OAAO;YACR,OAAO,CAAC,OAAO,IAAI,2BAA2B,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,QAAQ,CACV,MAAc,EACd,OAAsB;QAEtB,MAAM,IAAI,GAA4B;YAClC,KAAK,EAAE,IAAI,CAAC,YAAY;YACxB,UAAU,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI;YACtC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;SAChD,CAAC;QAEF,IAAI,OAAO,EAAE,YAAY,EAAE;YACvB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;SACtC;QAED,IAAI,OAAO,EAAE,WAAW,KAAK,SAAS,EAAE;YACpC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;SAC1C;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,cAAc,EAAE;YACxD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACL,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,IAAI,CAAC,MAAM;gBACxB,mBAAmB,EAAE,YAAY;aACpC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC7B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;YACd,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CACX,qBAAqB,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,CACxD,CAAC;SACL;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAsB,CAAC;QAE1D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO;aACvB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;aACxC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;aAChC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEhB,OAAO;YACH,OAAO;YACP,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY;YACpC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa;YACtC,KAAK,EAAE,IAAI,CAAC,KAAK;SACpB,CAAC;IACN,CAAC;IAED,aAAa;QACT,OAAO,QAAQ,CAAC;IACpB,CAAC;CACJ;AAjED,oCAiEC"}
@@ -0,0 +1,3 @@
1
+ export { ClaudeDriver } from "./claude.driver";
2
+ export type { ClaudeDriverOptions } from "./claude.driver";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai-agent/drivers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClaudeDriver = void 0;
4
+ var claude_driver_1 = require("./claude.driver");
5
+ Object.defineProperty(exports, "ClaudeDriver", { enumerable: true, get: function () { return claude_driver_1.ClaudeDriver; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ai-agent/drivers/index.ts"],"names":[],"mappings":";;;AAAA,iDAA+C;AAAtC,6GAAA,YAAY,OAAA"}
@@ -0,0 +1,5 @@
1
+ export * from "./ai-agent";
2
+ export * from "./ai-agent.types";
3
+ export * from "./drivers";
4
+ export * from "./driver.registry";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai-agent/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./ai-agent"), exports);
18
+ __exportStar(require("./ai-agent.types"), exports);
19
+ __exportStar(require("./drivers"), exports);
20
+ __exportStar(require("./driver.registry"), exports);
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai-agent/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,mDAAiC;AACjC,4CAA0B;AAC1B,oDAAkC"}
@@ -3,6 +3,11 @@ import type { FastifyPluginAsync } from "fastify";
3
3
  declare module "fastify" {
4
4
  interface FastifyInstance {
5
5
  kc: KeycloakAdminClient;
6
+ kcAdminState: {
7
+ connected: boolean;
8
+ lastError: unknown | null;
9
+ lastAuthAt: Date | null;
10
+ };
6
11
  }
7
12
  }
8
13
  export interface KeycloakAdminPluginOptions {
@@ -10,6 +15,8 @@ export interface KeycloakAdminPluginOptions {
10
15
  realmName: string;
11
16
  clientId: string;
12
17
  clientSecret: string;
18
+ retryDelayMs?: number;
19
+ failOnStartup?: boolean;
13
20
  }
14
21
  export declare const keycloakAdminPlugin: FastifyPluginAsync<KeycloakAdminPluginOptions>;
15
22
  export default keycloakAdminPlugin;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/keycloak-admin/index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,iCAAiC,CAAC;AAElE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAIlD,OAAO,QAAQ,SAAS,CAAC;IACrB,UAAU,eAAe;QACrB,EAAE,EAAE,mBAAmB,CAAC;KAC3B;CACJ;AAMD,MAAM,WAAW,0BAA0B;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACxB;AAiFD,eAAO,MAAM,mBAAmB,gDAE9B,CAAC;AAEH,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/keycloak-admin/index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,iCAAiC,CAAC;AAElE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAIlD,OAAO,QAAQ,SAAS,CAAC;IACrB,UAAU,eAAe;QACrB,EAAE,EAAE,mBAAmB,CAAC;QACxB,YAAY,EAAE;YACV,SAAS,EAAE,OAAO,CAAC;YACnB,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;YAC1B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;SAC3B,CAAC;KACL;CACJ;AAMD,MAAM,WAAW,0BAA0B;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B;AAwID,eAAO,MAAM,mBAAmB,gDAE9B,CAAC;AAEH,eAAe,mBAAmB,CAAC"}
@@ -15,58 +15,101 @@ function getTokenExpirationMilliseconds(accessToken) {
15
15
  if (!decoded?.exp) {
16
16
  return 0;
17
17
  }
18
- return decoded.exp * 1000 - Date.now();
18
+ return Math.max(decoded.exp * 1000 - Date.now(), 0);
19
19
  }
20
- const keycloakAdminPluginAsync = async (instance, options) => {
21
- instance.log.info("Initializing Keycloak Admin Client");
22
- try {
23
- if (!instance.kc) {
24
- const kc = new keycloak_admin_client_1.default({
25
- baseUrl: options.baseUrl,
26
- realmName: options.realmName
27
- });
28
- const credentials = {
29
- grantType: "client_credentials",
30
- clientId: options.clientId,
31
- clientSecret: options.clientSecret
32
- };
33
- await loopConnect(kc, credentials);
34
- instance.decorate("kc", kc);
35
- const accessTokenLifespan = getTokenExpirationMilliseconds(kc.accessToken);
36
- const refreshIntervalMs = accessTokenLifespan > 0
37
- ? Math.floor(accessTokenLifespan * 0.9)
20
+ async function authenticate(kc, credentials) {
21
+ await kc.auth(credentials);
22
+ return getTokenExpirationMilliseconds(kc.accessToken);
23
+ }
24
+ const keycloakAdminPluginAsync = async (fastify, options) => {
25
+ fastify.log.info("Initializing Keycloak Admin Client");
26
+ const kc = new keycloak_admin_client_1.default({
27
+ baseUrl: options.baseUrl,
28
+ realmName: options.realmName,
29
+ });
30
+ const credentials = {
31
+ grantType: "client_credentials",
32
+ clientId: options.clientId,
33
+ clientSecret: options.clientSecret,
34
+ };
35
+ const state = {
36
+ connected: false,
37
+ lastError: null,
38
+ lastAuthAt: null,
39
+ };
40
+ fastify.decorate("kc", kc);
41
+ fastify.decorate("kcAdminState", state);
42
+ const retryDelayMs = options.retryDelayMs ?? 5000;
43
+ const failOnStartup = options.failOnStartup ?? false;
44
+ let stopped = false;
45
+ let timer = null;
46
+ let running = false;
47
+ const scheduleNext = (delayMs) => {
48
+ if (stopped)
49
+ return;
50
+ timer = setTimeout(() => {
51
+ void authLoop();
52
+ }, delayMs);
53
+ };
54
+ const authLoop = async () => {
55
+ if (stopped || running)
56
+ return;
57
+ running = true;
58
+ try {
59
+ const tokenLifespanMs = await authenticate(kc, credentials);
60
+ state.connected = true;
61
+ state.lastError = null;
62
+ state.lastAuthAt = new Date();
63
+ const nextRefreshMs = tokenLifespanMs > 0
64
+ ? Math.max(Math.floor(tokenLifespanMs * 0.9), 10000)
38
65
  : 60000;
39
- instance.log.info({
40
- accessTokenLifespanSeconds: Math.floor(accessTokenLifespan / 1000),
41
- refreshIntervalSeconds: Math.floor(refreshIntervalMs / 1000)
42
- }, "Keycloak Admin Client initialized");
43
- const refreshTokenInterval = setInterval(() => {
44
- void kc.auth(credentials);
45
- }, refreshIntervalMs);
46
- instance.addHook("onClose", (_fastify, done) => {
47
- clearInterval(refreshTokenInterval);
48
- done();
49
- });
66
+ fastify.log.info({
67
+ tokenLifespanSeconds: Math.floor(tokenLifespanMs / 1000),
68
+ nextRefreshSeconds: Math.floor(nextRefreshMs / 1000),
69
+ }, "Keycloak Admin Client authenticated");
70
+ scheduleNext(nextRefreshMs);
50
71
  }
51
- }
52
- catch (error) {
53
- instance.log.error(error, "Error initializing Keycloak Admin Client");
54
- }
55
- };
56
- async function loopConnect(kc, credentials) {
57
- while (true) {
72
+ catch (error) {
73
+ state.connected = false;
74
+ state.lastError = error;
75
+ fastify.log.error(error, "Keycloak Admin Client auth failed, retrying");
76
+ scheduleNext(retryDelayMs);
77
+ }
78
+ finally {
79
+ running = false;
80
+ }
81
+ };
82
+ if (failOnStartup) {
58
83
  try {
59
- await kc.auth(credentials);
60
- break;
84
+ const tokenLifespanMs = await authenticate(kc, credentials);
85
+ state.connected = true;
86
+ state.lastError = null;
87
+ state.lastAuthAt = new Date();
88
+ const nextRefreshMs = tokenLifespanMs > 0
89
+ ? Math.max(Math.floor(tokenLifespanMs * 0.9), 10000)
90
+ : 60000;
91
+ scheduleNext(nextRefreshMs);
61
92
  }
62
93
  catch (error) {
63
- console.error(error, "Error refreshing Keycloak Admin Client token, retrying in 5 seconds");
64
- await new Promise(resolve => setTimeout(resolve, 5000));
94
+ fastify.log.error(error, "Failed to authenticate Keycloak on startup");
95
+ throw error;
65
96
  }
66
97
  }
67
- }
98
+ else {
99
+ void authLoop();
100
+ }
101
+ fastify.addHook("onClose", (_instance, done) => {
102
+ stopped = true;
103
+ if (timer) {
104
+ clearTimeout(timer);
105
+ timer = null;
106
+ }
107
+ done();
108
+ });
109
+ fastify.log.info("Keycloak Admin plugin initialized");
110
+ };
68
111
  exports.keycloakAdminPlugin = (0, fastify_plugin_1.default)(keycloakAdminPluginAsync, {
69
- name: "inobeta-keycloak-admin"
112
+ name: "inobeta-keycloak-admin",
70
113
  });
71
114
  exports.default = exports.keycloakAdminPlugin;
72
115
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/keycloak-admin/index.ts"],"names":[],"mappings":";;;;;;AAAA,4FAAkE;AAGlE,oEAA2C;AAC3C,gEAA+B;AAmB/B,SAAS,8BAA8B,CAAC,WAAoB;IACxD,IAAI,CAAC,WAAW,EAAE;QACd,OAAO,CAAC,CAAC;KACZ;IAED,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,WAAW,CAAsB,CAAC;IAE7D,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;QACf,OAAO,CAAC,CAAC;KACZ;IAED,OAAO,OAAO,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC3C,CAAC;AAED,MAAM,wBAAwB,GAE1B,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;IAC5B,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;IAExD,IAAI;QACA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;YACd,MAAM,EAAE,GAAG,IAAI,+BAAmB,CAAC;gBAC/B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,SAAS,EAAE,OAAO,CAAC,SAAS;aAC/B,CAAC,CAAC;YAEH,MAAM,WAAW,GAAG;gBAChB,SAAS,EAAE,oBAA6B;gBACxC,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;aACrC,CAAC;YAEF,MAAM,WAAW,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;YACnC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAE5B,MAAM,mBAAmB,GAAG,8BAA8B,CACtD,EAAE,CAAC,WAAW,CACjB,CAAC;YAEF,MAAM,iBAAiB,GACnB,mBAAmB,GAAG,CAAC;gBACnB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,GAAG,CAAC;gBACvC,CAAC,CAAC,KAAM,CAAC;YAEjB,QAAQ,CAAC,GAAG,CAAC,IAAI,CACb;gBACI,0BAA0B,EAAE,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAC;gBAClE,sBAAsB,EAAE,IAAI,CAAC,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC;aAC/D,EACD,mCAAmC,CACtC,CAAC;YAEF,MAAM,oBAAoB,GAAG,WAAW,CAAC,GAAG,EAAE;gBAC1C,KAAK,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC9B,CAAC,EAAE,iBAAiB,CAAC,CAAC;YAEtB,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE;gBAC3C,aAAa,CAAC,oBAAoB,CAAC,CAAC;gBACpC,IAAI,EAAE,CAAC;YACX,CAAC,CAAC,CAAC;SACN;KACJ;IAAC,OAAO,KAAK,EAAE;QACZ,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,0CAA0C,CAAC,CAAC;KACzE;AACL,CAAC,CAAC;AAGF,KAAK,UAAU,WAAW,CAAC,EAAuB,EAAE,WAAwB;IACxE,OAAO,IAAI,EAAE;QACT,IAAI;YACA,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC3B,MAAM;SACT;QAAC,OAAO,KAAK,EAAE;YACZ,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,qEAAqE,CAAC,CAAC;YAC5F,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAK,CAAC,CAAC,CAAC;SAC5D;KACJ;AACL,CAAC;AAEY,QAAA,mBAAmB,GAAG,IAAA,wBAAa,EAAC,wBAAwB,EAAE;IACvE,IAAI,EAAE,wBAAwB;CACjC,CAAC,CAAC;AAEH,kBAAe,2BAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/keycloak-admin/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inobeta/api",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Shared backend library for Inobeta projects",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",