@agentuity/server 0.0.4 → 0.0.6
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/AGENTS.md +29 -96
- package/README.md +31 -198
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +22 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +107 -0
- package/dist/server.js.map +1 -0
- package/package.json +11 -32
- package/dist/_config.d.ts +0 -61
- package/dist/_config.d.ts.map +0 -1
- package/dist/_context.d.ts +0 -33
- package/dist/_context.d.ts.map +0 -1
- package/dist/_idle.d.ts +0 -7
- package/dist/_idle.d.ts.map +0 -1
- package/dist/_server.d.ts +0 -17
- package/dist/_server.d.ts.map +0 -1
- package/dist/_services.d.ts +0 -2
- package/dist/_services.d.ts.map +0 -1
- package/dist/_util.d.ts +0 -16
- package/dist/_util.d.ts.map +0 -1
- package/dist/_waituntil.d.ts +0 -20
- package/dist/_waituntil.d.ts.map +0 -1
- package/dist/agent.d.ts +0 -88
- package/dist/agent.d.ts.map +0 -1
- package/dist/app.d.ts +0 -24
- package/dist/app.d.ts.map +0 -1
- package/dist/logger/console.d.ts +0 -50
- package/dist/logger/console.d.ts.map +0 -1
- package/dist/logger/index.d.ts +0 -4
- package/dist/logger/index.d.ts.map +0 -1
- package/dist/logger/internal.d.ts +0 -79
- package/dist/logger/internal.d.ts.map +0 -1
- package/dist/logger/logger.d.ts +0 -41
- package/dist/logger/logger.d.ts.map +0 -1
- package/dist/logger/user.d.ts +0 -8
- package/dist/logger/user.d.ts.map +0 -1
- package/dist/logger/util.d.ts +0 -11
- package/dist/logger/util.d.ts.map +0 -1
- package/dist/otel/config.d.ts +0 -17
- package/dist/otel/config.d.ts.map +0 -1
- package/dist/otel/console.d.ts +0 -26
- package/dist/otel/console.d.ts.map +0 -1
- package/dist/otel/fetch.d.ts +0 -12
- package/dist/otel/fetch.d.ts.map +0 -1
- package/dist/otel/http.d.ts +0 -16
- package/dist/otel/http.d.ts.map +0 -1
- package/dist/otel/logger.d.ts +0 -36
- package/dist/otel/logger.d.ts.map +0 -1
- package/dist/otel/otel.d.ts +0 -58
- package/dist/otel/otel.d.ts.map +0 -1
- package/dist/router.d.ts +0 -37
- package/dist/router.d.ts.map +0 -1
- package/src/_config.ts +0 -101
- package/src/_context.ts +0 -88
- package/src/_idle.ts +0 -26
- package/src/_server.ts +0 -278
- package/src/_services.ts +0 -175
- package/src/_util.ts +0 -63
- package/src/_waituntil.ts +0 -246
- package/src/agent.ts +0 -287
- package/src/app.ts +0 -31
- package/src/index.ts +0 -5
- package/src/logger/console.ts +0 -111
- package/src/logger/index.ts +0 -3
- package/src/logger/internal.ts +0 -165
- package/src/logger/logger.ts +0 -44
- package/src/logger/user.ts +0 -11
- package/src/logger/util.ts +0 -80
- package/src/otel/config.ts +0 -81
- package/src/otel/console.ts +0 -56
- package/src/otel/fetch.ts +0 -103
- package/src/otel/http.ts +0 -51
- package/src/otel/logger.ts +0 -238
- package/src/otel/otel.ts +0 -317
- package/src/router.ts +0 -303
package/src/_waituntil.ts
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
import { context, SpanStatusCode, type Tracer, trace } from '@opentelemetry/api';
|
|
2
|
-
import type { Logger } from './logger';
|
|
3
|
-
import { internal } from './logger/internal';
|
|
4
|
-
|
|
5
|
-
let running = 0;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* returns true if wait until is pending
|
|
9
|
-
* @returns boolean
|
|
10
|
-
*/
|
|
11
|
-
export function hasWaitUntilPending(): boolean {
|
|
12
|
-
internal.debug('hasWaitUntilPending called: %d', running);
|
|
13
|
-
return running > 0;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export default class WaitUntilHandler {
|
|
17
|
-
private promises: Promise<void>[];
|
|
18
|
-
private tracer: Tracer;
|
|
19
|
-
private started: number | undefined;
|
|
20
|
-
private hasCalledWaitUntilAll = false;
|
|
21
|
-
private setHeader: (k: string, v: string) => void;
|
|
22
|
-
|
|
23
|
-
public constructor(setHeader: (k: string, v: string) => void, tracer: Tracer) {
|
|
24
|
-
this.tracer = tracer;
|
|
25
|
-
this.promises = [];
|
|
26
|
-
this.setHeader = setHeader;
|
|
27
|
-
this.hasCalledWaitUntilAll = false;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public waitUntil(promise: Promise<void> | (() => void | Promise<void>)): void {
|
|
31
|
-
if (this.hasCalledWaitUntilAll) {
|
|
32
|
-
throw new Error('Cannot call waitUntil after waitUntilAll has been called');
|
|
33
|
-
}
|
|
34
|
-
this.setHeader('x-agentuity-session-pending', 'true');
|
|
35
|
-
running++;
|
|
36
|
-
internal.debug('wait until called, running: %d', running);
|
|
37
|
-
const currentContext = context.active();
|
|
38
|
-
|
|
39
|
-
// Start execution immediately, don't defer it
|
|
40
|
-
const executingPromise = (async () => {
|
|
41
|
-
if (this.started === undefined) {
|
|
42
|
-
this.started = Date.now(); /// this first execution marks the start time
|
|
43
|
-
}
|
|
44
|
-
const span = this.tracer.startSpan('waitUntil', {}, currentContext);
|
|
45
|
-
const spanContext = trace.setSpan(currentContext, span);
|
|
46
|
-
try {
|
|
47
|
-
internal.debug('starting waituntil');
|
|
48
|
-
await context.with(spanContext, async () => {
|
|
49
|
-
const resolvedPromise = typeof promise === 'function' ? promise() : promise;
|
|
50
|
-
return await Promise.resolve(resolvedPromise);
|
|
51
|
-
});
|
|
52
|
-
internal.debug('completed waituntil');
|
|
53
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
54
|
-
} catch (ex: unknown) {
|
|
55
|
-
span.recordException(ex as Error);
|
|
56
|
-
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
57
|
-
throw ex;
|
|
58
|
-
} finally {
|
|
59
|
-
span.end();
|
|
60
|
-
}
|
|
61
|
-
// NOTE: we only decrement when the promise is removed from the array in waitUntilAll
|
|
62
|
-
})();
|
|
63
|
-
|
|
64
|
-
// Store the executing promise for cleanup tracking
|
|
65
|
-
this.promises.push(executingPromise);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
public hasPending(): boolean {
|
|
69
|
-
return this.promises.length > 0;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private async markSessionCompleted(sessionId: string, duration: number) {
|
|
73
|
-
// TODO:
|
|
74
|
-
internal.debug('markSessionCompleted sessionId: %s, duration: %dms', sessionId, duration);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
public async waitUntilAll(logger: Logger, sessionId: string): Promise<void> {
|
|
78
|
-
internal.debug(`🔍 waitUntilAll() called for session ${sessionId} (count: %d)`, running);
|
|
79
|
-
|
|
80
|
-
if (this.hasCalledWaitUntilAll) {
|
|
81
|
-
throw new Error('waitUntilAll can only be called once per instance');
|
|
82
|
-
}
|
|
83
|
-
this.hasCalledWaitUntilAll = true;
|
|
84
|
-
|
|
85
|
-
if (this.promises.length === 0) {
|
|
86
|
-
internal.debug('No promises to wait for, executing evals directly');
|
|
87
|
-
// await this.executeEvalsForSession(logger, sessionId);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
internal.debug(`⏳ Waiting for ${this.promises.length} promises to complete...`);
|
|
92
|
-
try {
|
|
93
|
-
// Promises are already executing, just wait for them to complete
|
|
94
|
-
await Promise.all(this.promises);
|
|
95
|
-
const duration = Date.now() - (this.started as number);
|
|
96
|
-
internal.debug('✅ All promises completed, marking session completed');
|
|
97
|
-
await this.markSessionCompleted(sessionId, duration);
|
|
98
|
-
|
|
99
|
-
// // Execute evals after session completion
|
|
100
|
-
// internal.debug('🚀 Starting eval execution after session completion');
|
|
101
|
-
// await this.executeEvalsForSession(logger, sessionId);
|
|
102
|
-
} catch (ex) {
|
|
103
|
-
logger.error('error sending session completed', ex);
|
|
104
|
-
} finally {
|
|
105
|
-
running -= this.promises.length;
|
|
106
|
-
this.promises.length = 0;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// /**
|
|
111
|
-
// * Execute evals for the completed session
|
|
112
|
-
// */
|
|
113
|
-
// private async executeEvalsForSession(
|
|
114
|
-
// logger: Logger,
|
|
115
|
-
// sessionId: string
|
|
116
|
-
// ): Promise<void> {
|
|
117
|
-
// try {
|
|
118
|
-
// internal.debug(`🔍 Starting eval execution for session ${sessionId}`);
|
|
119
|
-
|
|
120
|
-
// // Get pending eval jobs for this session
|
|
121
|
-
// internal.debug('🔍 Getting EvalJobScheduler instance...');
|
|
122
|
-
// const evalJobScheduler = await EvalJobScheduler.getInstance();
|
|
123
|
-
// internal.debug('✅ EvalJobScheduler instance obtained');
|
|
124
|
-
|
|
125
|
-
// internal.debug(`🔍 Querying jobs for session ${sessionId}...`);
|
|
126
|
-
// const jobs = evalJobScheduler.getJobs({ sessionId });
|
|
127
|
-
|
|
128
|
-
// if (jobs.length === 0) {
|
|
129
|
-
// internal.debug(`📭 No eval jobs found for session ${sessionId}`);
|
|
130
|
-
// return;
|
|
131
|
-
// }
|
|
132
|
-
|
|
133
|
-
// internal.debug(
|
|
134
|
-
// `📋 Found ${jobs.length} eval jobs for session ${sessionId}`
|
|
135
|
-
// );
|
|
136
|
-
|
|
137
|
-
// // Load eval metadata map
|
|
138
|
-
// internal.debug('🔧 Loading eval metadata map...');
|
|
139
|
-
// const evalAPI = new EvalAPI();
|
|
140
|
-
// const evalMetadataMap = await evalAPI.loadEvalMetadataMap();
|
|
141
|
-
// internal.debug(`📚 Loaded ${evalMetadataMap.size} eval mappings`);
|
|
142
|
-
|
|
143
|
-
// // Execute evals for each job
|
|
144
|
-
// let totalEvalsExecuted = 0;
|
|
145
|
-
// for (let i = 0; i < jobs.length; i++) {
|
|
146
|
-
// const job = jobs[i];
|
|
147
|
-
// internal.debug(
|
|
148
|
-
// `🎯 Processing job ${i + 1}/${jobs.length} (spanId: ${job.spanId})`
|
|
149
|
-
// );
|
|
150
|
-
// const evalsInJob = await this.executeEvalsForJob(
|
|
151
|
-
// logger,
|
|
152
|
-
// job,
|
|
153
|
-
// evalAPI,
|
|
154
|
-
// evalMetadataMap
|
|
155
|
-
// );
|
|
156
|
-
// totalEvalsExecuted += evalsInJob;
|
|
157
|
-
// internal.debug(
|
|
158
|
-
// `✅ Completed job ${i + 1}/${jobs.length}: ${evalsInJob} evals executed`
|
|
159
|
-
// );
|
|
160
|
-
// }
|
|
161
|
-
|
|
162
|
-
// internal.debug(
|
|
163
|
-
// `✅ Completed eval execution for session ${sessionId}: ${totalEvalsExecuted} evals executed`
|
|
164
|
-
// );
|
|
165
|
-
|
|
166
|
-
// // Clean up completed jobs
|
|
167
|
-
// internal.debug(`🧹 Cleaning up ${jobs.length} completed jobs...`);
|
|
168
|
-
// for (const job of jobs) {
|
|
169
|
-
// evalJobScheduler.removeJob(job.spanId);
|
|
170
|
-
// }
|
|
171
|
-
// internal.debug(`✅ Cleaned up ${jobs.length} completed jobs`);
|
|
172
|
-
// } catch (error) {
|
|
173
|
-
// logger.error('❌ Error executing evals for session:', error);
|
|
174
|
-
// }
|
|
175
|
-
// }
|
|
176
|
-
|
|
177
|
-
// /**
|
|
178
|
-
// * Execute evals for a specific job
|
|
179
|
-
// */
|
|
180
|
-
// private async executeEvalsForJob(
|
|
181
|
-
// logger: Logger,
|
|
182
|
-
// job: {
|
|
183
|
-
// spanId: string;
|
|
184
|
-
// sessionId: string;
|
|
185
|
-
// promptMetadata: PromptAttributes[];
|
|
186
|
-
// input?: string;
|
|
187
|
-
// output?: string;
|
|
188
|
-
// },
|
|
189
|
-
// evalAPI: EvalAPI,
|
|
190
|
-
// evalMetadataMap: Map<string, string>
|
|
191
|
-
// ): Promise<number> {
|
|
192
|
-
// let evalsExecuted = 0;
|
|
193
|
-
|
|
194
|
-
// internal.debug(
|
|
195
|
-
// `🎯 Processing job ${job.spanId} with ${job.promptMetadata.length} prompt metadata entries`
|
|
196
|
-
// );
|
|
197
|
-
|
|
198
|
-
// for (const promptMeta of job.promptMetadata || []) {
|
|
199
|
-
// if (!promptMeta.evals || promptMeta.evals.length === 0) {
|
|
200
|
-
// logger.debug('⏭️ Skipping prompt metadata with no evals');
|
|
201
|
-
// continue;
|
|
202
|
-
// }
|
|
203
|
-
|
|
204
|
-
// internal.debug(
|
|
205
|
-
// `📝 Found ${promptMeta.evals.length} evals for prompt: ${promptMeta.evals.join(', ')}`
|
|
206
|
-
// );
|
|
207
|
-
|
|
208
|
-
// for (const evalSlug of promptMeta.evals) {
|
|
209
|
-
// try {
|
|
210
|
-
// internal.debug(
|
|
211
|
-
// `🚀 Running eval '${evalSlug}' for session ${job.sessionId}`
|
|
212
|
-
// );
|
|
213
|
-
|
|
214
|
-
// internal.debug(`🔑 Template hash: ${promptMeta.templateHash}`);
|
|
215
|
-
// internal.debug(`🔑 Compiled hash: ${promptMeta.compiledHash}`);
|
|
216
|
-
|
|
217
|
-
// const result = await evalAPI.runEval(
|
|
218
|
-
// evalSlug,
|
|
219
|
-
// job.input || '',
|
|
220
|
-
// job.output || '',
|
|
221
|
-
// job.sessionId,
|
|
222
|
-
// job.spanId,
|
|
223
|
-
// promptMeta.templateHash
|
|
224
|
-
// );
|
|
225
|
-
|
|
226
|
-
// if (result.success) {
|
|
227
|
-
// internal.debug(`✅ Successfully executed eval '${evalSlug}'`);
|
|
228
|
-
// evalsExecuted++;
|
|
229
|
-
// } else {
|
|
230
|
-
// logger.warn(
|
|
231
|
-
// `⚠️ Eval '${evalSlug}' completed but returned error: ${result.message}`
|
|
232
|
-
// );
|
|
233
|
-
// }
|
|
234
|
-
// } catch (error) {
|
|
235
|
-
// logger.error(`❌ Failed to execute eval '${evalSlug}':`, error);
|
|
236
|
-
// // Continue with other evals even if one fails
|
|
237
|
-
// }
|
|
238
|
-
// }
|
|
239
|
-
// }
|
|
240
|
-
|
|
241
|
-
// internal.debug(
|
|
242
|
-
// `📊 Job ${job.spanId} completed: ${evalsExecuted} evals executed`
|
|
243
|
-
// );
|
|
244
|
-
// return evalsExecuted;
|
|
245
|
-
// }
|
|
246
|
-
}
|
package/src/agent.ts
DELETED
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import type {
|
|
3
|
-
StandardSchemaV1,
|
|
4
|
-
KeyValueStorage,
|
|
5
|
-
ObjectStorage,
|
|
6
|
-
StreamStorage,
|
|
7
|
-
VectorStorage,
|
|
8
|
-
} from '@agentuity/core';
|
|
9
|
-
import { trace, type Tracer } from '@opentelemetry/api';
|
|
10
|
-
|
|
11
|
-
import type { Context, MiddlewareHandler } from 'hono';
|
|
12
|
-
import { getAgentContext, runInAgentContext, type RequestAgentContextArgs } from './_context';
|
|
13
|
-
import type { Logger } from './logger';
|
|
14
|
-
|
|
15
|
-
export interface AgentContext {
|
|
16
|
-
// email: () => Promise<Email | null>;
|
|
17
|
-
// sms: () => Promise<SMS | null>;
|
|
18
|
-
// cron: () => Promise<Cron | null>;
|
|
19
|
-
waitUntil: (promise: Promise<void> | (() => void | Promise<void>)) => void;
|
|
20
|
-
agent?: any; // Will be augmented by generated code
|
|
21
|
-
current?: any; // Will be augmented by generated code
|
|
22
|
-
agentName?: AgentName;
|
|
23
|
-
logger: Logger;
|
|
24
|
-
sessionId: string;
|
|
25
|
-
tracer: Tracer;
|
|
26
|
-
kv: KeyValueStorage;
|
|
27
|
-
objectstore: ObjectStorage;
|
|
28
|
-
stream: StreamStorage;
|
|
29
|
-
vector: VectorStorage;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface AgentMetadata {
|
|
33
|
-
/**
|
|
34
|
-
* the unique identifier for this agent and project
|
|
35
|
-
*/
|
|
36
|
-
id: string;
|
|
37
|
-
/**
|
|
38
|
-
* the folder name for the agent
|
|
39
|
-
*/
|
|
40
|
-
identifier: string;
|
|
41
|
-
/**
|
|
42
|
-
* the human readable name for the agent (identifier is used if not specified)
|
|
43
|
-
*/
|
|
44
|
-
name: string;
|
|
45
|
-
/**
|
|
46
|
-
* the human readable description for the agent (empty if not provided)
|
|
47
|
-
*/
|
|
48
|
-
description: string;
|
|
49
|
-
/**
|
|
50
|
-
* the relative path to the agent from the root project directory
|
|
51
|
-
*/
|
|
52
|
-
filename: string;
|
|
53
|
-
/**
|
|
54
|
-
* a unique version for the agent. computed as the SHA256 contents of the file.
|
|
55
|
-
*/
|
|
56
|
-
version: string;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* The Agent handler interface.
|
|
61
|
-
*/
|
|
62
|
-
export type Agent<
|
|
63
|
-
TInput extends StandardSchemaV1 | undefined = any,
|
|
64
|
-
TOutput extends StandardSchemaV1 | undefined = any,
|
|
65
|
-
TStream extends boolean = false,
|
|
66
|
-
> = {
|
|
67
|
-
metadata: AgentMetadata;
|
|
68
|
-
handler: (ctx: AgentContext, ...args: any[]) => any | Promise<any>;
|
|
69
|
-
} & (TInput extends StandardSchemaV1 ? { inputSchema: TInput } : { inputSchema?: never }) &
|
|
70
|
-
(TOutput extends StandardSchemaV1 ? { outputSchema: TOutput } : { outputSchema?: never }) &
|
|
71
|
-
(TStream extends true ? { stream: true } : { stream?: false });
|
|
72
|
-
|
|
73
|
-
type InferSchemaInput<T> = T extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<T> : never;
|
|
74
|
-
|
|
75
|
-
type InferStreamOutput<TOutput, TStream extends boolean> = TStream extends true
|
|
76
|
-
? TOutput extends StandardSchemaV1
|
|
77
|
-
? ReadableStream<StandardSchemaV1.InferOutput<TOutput>>
|
|
78
|
-
: ReadableStream<unknown>
|
|
79
|
-
: TOutput extends StandardSchemaV1
|
|
80
|
-
? StandardSchemaV1.InferOutput<TOutput>
|
|
81
|
-
: void;
|
|
82
|
-
|
|
83
|
-
export interface AgentRunner<
|
|
84
|
-
TInput extends StandardSchemaV1 | undefined = any,
|
|
85
|
-
TOutput extends StandardSchemaV1 | undefined = any,
|
|
86
|
-
TStream extends boolean = false,
|
|
87
|
-
> {
|
|
88
|
-
metadata: AgentMetadata;
|
|
89
|
-
run: undefined extends TInput
|
|
90
|
-
? () => Promise<InferStreamOutput<Exclude<TOutput, undefined>, TStream>>
|
|
91
|
-
: (
|
|
92
|
-
input: InferSchemaInput<Exclude<TInput, undefined>>
|
|
93
|
-
) => Promise<InferStreamOutput<Exclude<TOutput, undefined>, TStream>>;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Will be populated at runtime with strongly typed agents
|
|
97
|
-
const agents = new Map<string, Agent>();
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Union type of all registered agent names.
|
|
101
|
-
* Falls back to `string` when no agents are registered (before augmentation).
|
|
102
|
-
* After augmentation, this becomes a strict union of agent names for full type safety.
|
|
103
|
-
*/
|
|
104
|
-
export type AgentName = string;
|
|
105
|
-
export type AgentRegistry = Record<AgentName, AgentRunner>;
|
|
106
|
-
|
|
107
|
-
export const registerAgent = (name: AgentName, agent: Agent): void => {
|
|
108
|
-
agents.set(name, agent);
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
export function createAgent<
|
|
112
|
-
TInput extends StandardSchemaV1 | undefined = undefined,
|
|
113
|
-
TOutput extends StandardSchemaV1 | undefined = undefined,
|
|
114
|
-
TStream extends boolean = false,
|
|
115
|
-
>(config: {
|
|
116
|
-
schema?: {
|
|
117
|
-
input?: TInput;
|
|
118
|
-
output?: TOutput;
|
|
119
|
-
stream?: TStream;
|
|
120
|
-
};
|
|
121
|
-
metadata?: Partial<Omit<AgentMetadata, 'id'>>;
|
|
122
|
-
handler: TInput extends StandardSchemaV1
|
|
123
|
-
? TStream extends true
|
|
124
|
-
? TOutput extends StandardSchemaV1
|
|
125
|
-
? (
|
|
126
|
-
c: AgentContext,
|
|
127
|
-
input: StandardSchemaV1.InferOutput<TInput>
|
|
128
|
-
) =>
|
|
129
|
-
| Promise<ReadableStream<StandardSchemaV1.InferOutput<TOutput>>>
|
|
130
|
-
| ReadableStream<StandardSchemaV1.InferOutput<TOutput>>
|
|
131
|
-
: (
|
|
132
|
-
c: AgentContext,
|
|
133
|
-
input: StandardSchemaV1.InferOutput<TInput>
|
|
134
|
-
) => Promise<ReadableStream<unknown>> | ReadableStream<unknown>
|
|
135
|
-
: TOutput extends StandardSchemaV1
|
|
136
|
-
? (
|
|
137
|
-
c: AgentContext,
|
|
138
|
-
input: StandardSchemaV1.InferOutput<TInput>
|
|
139
|
-
) =>
|
|
140
|
-
| Promise<StandardSchemaV1.InferOutput<TOutput>>
|
|
141
|
-
| StandardSchemaV1.InferOutput<TOutput>
|
|
142
|
-
: (c: AgentContext, input: StandardSchemaV1.InferOutput<TInput>) => Promise<void> | void
|
|
143
|
-
: TStream extends true
|
|
144
|
-
? TOutput extends StandardSchemaV1
|
|
145
|
-
? (
|
|
146
|
-
c: AgentContext
|
|
147
|
-
) =>
|
|
148
|
-
| Promise<ReadableStream<StandardSchemaV1.InferOutput<TOutput>>>
|
|
149
|
-
| ReadableStream<StandardSchemaV1.InferOutput<TOutput>>
|
|
150
|
-
: (c: AgentContext) => Promise<ReadableStream<unknown>> | ReadableStream<unknown>
|
|
151
|
-
: TOutput extends StandardSchemaV1
|
|
152
|
-
? (
|
|
153
|
-
c: AgentContext
|
|
154
|
-
) =>
|
|
155
|
-
| Promise<StandardSchemaV1.InferOutput<TOutput>>
|
|
156
|
-
| StandardSchemaV1.InferOutput<TOutput>
|
|
157
|
-
: (c: AgentContext) => Promise<void> | void;
|
|
158
|
-
}): Agent<TInput, TOutput, TStream> {
|
|
159
|
-
const inputSchema = config.schema?.input;
|
|
160
|
-
const outputSchema = config.schema?.output;
|
|
161
|
-
|
|
162
|
-
const handler = async (_ctx: Context, input?: any) => {
|
|
163
|
-
let validatedInput: any = undefined;
|
|
164
|
-
|
|
165
|
-
if (inputSchema) {
|
|
166
|
-
const inputResult = await inputSchema['~standard'].validate(input);
|
|
167
|
-
if (inputResult.issues) {
|
|
168
|
-
throw new Error(
|
|
169
|
-
`Input validation failed: ${inputResult.issues.map((i: any) => i.message).join(', ')}`
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
validatedInput = inputResult.value;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const agentCtx = getAgentContext();
|
|
176
|
-
|
|
177
|
-
const result = inputSchema
|
|
178
|
-
? await (config.handler as any)(agentCtx, validatedInput)
|
|
179
|
-
: await (config.handler as any)(agentCtx);
|
|
180
|
-
|
|
181
|
-
if (outputSchema) {
|
|
182
|
-
const outputResult = await outputSchema['~standard'].validate(result);
|
|
183
|
-
if (outputResult.issues) {
|
|
184
|
-
throw new Error(
|
|
185
|
-
`Output validation failed: ${outputResult.issues.map((i: any) => i.message).join(', ')}`
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
return outputResult.value;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return result;
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
const agent: any = { handler, metadata: config.metadata };
|
|
195
|
-
|
|
196
|
-
if (inputSchema) {
|
|
197
|
-
agent.inputSchema = inputSchema;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (outputSchema) {
|
|
201
|
-
agent.outputSchema = outputSchema;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (config.schema?.stream) {
|
|
205
|
-
agent.stream = config.schema.stream;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return agent as Agent<TInput, TOutput, TStream>;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const createAgentRunner = <
|
|
212
|
-
TInput extends StandardSchemaV1 | undefined = any,
|
|
213
|
-
TOutput extends StandardSchemaV1 | undefined = any,
|
|
214
|
-
TStream extends boolean = false,
|
|
215
|
-
>(
|
|
216
|
-
agent: Agent<TInput, TOutput, TStream>,
|
|
217
|
-
ctx: Context
|
|
218
|
-
): AgentRunner<TInput, TOutput, TStream> => {
|
|
219
|
-
if (agent.inputSchema) {
|
|
220
|
-
return {
|
|
221
|
-
metadata: agent.metadata,
|
|
222
|
-
run: async (input: any) => {
|
|
223
|
-
return agent.handler(ctx as unknown as AgentContext, input);
|
|
224
|
-
},
|
|
225
|
-
} as AgentRunner<TInput, TOutput, TStream>;
|
|
226
|
-
} else {
|
|
227
|
-
return {
|
|
228
|
-
metadata: agent.metadata,
|
|
229
|
-
run: async () => {
|
|
230
|
-
return agent.handler(ctx as unknown as AgentContext);
|
|
231
|
-
},
|
|
232
|
-
} as AgentRunner<TInput, TOutput, TStream>;
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
export const createAgentMiddleware = (agentName: AgentName): MiddlewareHandler => {
|
|
237
|
-
return async (ctx, next) => {
|
|
238
|
-
// Populate agents object with strongly-typed keys
|
|
239
|
-
const agentsObj: any = {};
|
|
240
|
-
for (const [name, agentFn] of agents) {
|
|
241
|
-
agentsObj[name] = createAgentRunner(agentFn, ctx);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const args: Partial<RequestAgentContextArgs<AgentRegistry, any>> = {
|
|
245
|
-
agent: agentsObj,
|
|
246
|
-
current: agentsObj[agentName],
|
|
247
|
-
agentName,
|
|
248
|
-
logger: ctx.var.logger.child({ agent: agentName }),
|
|
249
|
-
tracer: ctx.var.tracer,
|
|
250
|
-
setHeader: (k: string, v: string) => ctx.res.headers.set(k, v),
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
const span = trace.getActiveSpan();
|
|
254
|
-
if (span?.spanContext) {
|
|
255
|
-
args.sessionId = span.spanContext().traceId;
|
|
256
|
-
} else {
|
|
257
|
-
args.sessionId = Bun.randomUUIDv7();
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return runInAgentContext(
|
|
261
|
-
ctx as unknown as Record<string, unknown>,
|
|
262
|
-
args as RequestAgentContextArgs<any, any>,
|
|
263
|
-
next
|
|
264
|
-
);
|
|
265
|
-
|
|
266
|
-
// FIXME
|
|
267
|
-
// ctx.email = async (): Promise<Email> => {
|
|
268
|
-
// return {
|
|
269
|
-
// address: 'test@example.com',
|
|
270
|
-
// name: 'Test User',
|
|
271
|
-
// html: '<p>Hello, world!</p>',
|
|
272
|
-
// text: 'Hello, world!',
|
|
273
|
-
// };
|
|
274
|
-
// };
|
|
275
|
-
// ctx.sms = async (): Promise<SMS> => {
|
|
276
|
-
// return {
|
|
277
|
-
// message: 'Hello, world!',
|
|
278
|
-
// number: '+1234567890',
|
|
279
|
-
// };
|
|
280
|
-
// };
|
|
281
|
-
// ctx.cron = async (): Promise<Cron> => {
|
|
282
|
-
// return {
|
|
283
|
-
// schedule: '0 0 * * *',
|
|
284
|
-
// };
|
|
285
|
-
// };
|
|
286
|
-
};
|
|
287
|
-
};
|
package/src/app.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { type Env as HonoEnv, Hono } from 'hono';
|
|
2
|
-
import { createServer, getLogger } from './_server';
|
|
3
|
-
import type { Logger } from './logger';
|
|
4
|
-
import { type Meter, type Tracer } from '@opentelemetry/api';
|
|
5
|
-
|
|
6
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
7
|
-
export interface AppConfig {
|
|
8
|
-
// currently empty but may be extended in the future
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface Variables {
|
|
12
|
-
logger: Logger;
|
|
13
|
-
meter: Meter;
|
|
14
|
-
tracer: Tracer;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface Env extends HonoEnv {
|
|
18
|
-
Variables: Variables;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* create a new app instance
|
|
23
|
-
*
|
|
24
|
-
* @returns App instance
|
|
25
|
-
*/
|
|
26
|
-
export function createApp(config?: AppConfig) {
|
|
27
|
-
const app = new Hono<Env>();
|
|
28
|
-
const server = createServer(app, config);
|
|
29
|
-
const logger = getLogger() as Logger;
|
|
30
|
-
return { app, server, logger };
|
|
31
|
-
}
|
package/src/index.ts
DELETED
package/src/logger/console.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { __originalConsole } from '../otel/logger';
|
|
2
|
-
import type { Logger } from './logger';
|
|
3
|
-
import { formatMessage } from './util';
|
|
4
|
-
|
|
5
|
-
const yellow = '\x1b[33m';
|
|
6
|
-
const green = '\x1b[32m';
|
|
7
|
-
const red = '\x1b[31m';
|
|
8
|
-
const black = '\x1b[1;30m';
|
|
9
|
-
const reset = '\x1b[0m';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Console implementation of the Logger interface
|
|
13
|
-
*/
|
|
14
|
-
export default class ConsoleLogger implements Logger {
|
|
15
|
-
private context: Record<string, unknown>;
|
|
16
|
-
private formatContext: boolean;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Creates a new console logger
|
|
20
|
-
*
|
|
21
|
-
* @param context - Initial context for the logger
|
|
22
|
-
*/
|
|
23
|
-
constructor(context: Record<string, unknown> = {}, formatContext = true) {
|
|
24
|
-
this.context = context;
|
|
25
|
-
this.formatContext = formatContext;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Log a debug message
|
|
30
|
-
*
|
|
31
|
-
* @param message - The message to log
|
|
32
|
-
* @param args - Additional arguments to log
|
|
33
|
-
*/
|
|
34
|
-
debug(message: unknown, ...args: unknown[]): void {
|
|
35
|
-
try {
|
|
36
|
-
const formattedMessage = formatMessage(this.formatContext, this.context, message, args);
|
|
37
|
-
__originalConsole.debug(`${black}[DEBUG]${reset} ${formattedMessage}`);
|
|
38
|
-
} catch (err) {
|
|
39
|
-
// Fallback to direct logging if formatting fails
|
|
40
|
-
__originalConsole.debug(`${black}[DEBUG]${reset} ${message}`, ...args);
|
|
41
|
-
__originalConsole.error('Error formatting log message:', err);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Log an info message
|
|
47
|
-
*
|
|
48
|
-
* @param message - The message to log
|
|
49
|
-
* @param args - Additional arguments to log
|
|
50
|
-
*/
|
|
51
|
-
info(message: unknown, ...args: unknown[]): void {
|
|
52
|
-
try {
|
|
53
|
-
const formattedMessage = formatMessage(this.formatContext, this.context, message, args);
|
|
54
|
-
__originalConsole.info(`${green}[INFO]${reset} ${formattedMessage}`);
|
|
55
|
-
} catch (err) {
|
|
56
|
-
// Fallback to direct logging if formatting fails
|
|
57
|
-
__originalConsole.info(`${green}[INFO]${reset} ${message}`, ...args);
|
|
58
|
-
__originalConsole.error('Error formatting log message:', err);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Log a warning message
|
|
64
|
-
*
|
|
65
|
-
* @param message - The message to log
|
|
66
|
-
* @param args - Additional arguments to log
|
|
67
|
-
*/
|
|
68
|
-
warn(message: unknown, ...args: unknown[]): void {
|
|
69
|
-
try {
|
|
70
|
-
const formattedMessage = formatMessage(this.formatContext, this.context, message, args);
|
|
71
|
-
__originalConsole.warn(`${yellow}[WARN]${reset} ${formattedMessage}`);
|
|
72
|
-
} catch (err) {
|
|
73
|
-
// Fallback to direct logging if formatting fails
|
|
74
|
-
__originalConsole.warn(`${yellow}[WARN]${reset} ${message}`, ...args);
|
|
75
|
-
__originalConsole.error('Error formatting log message:', err);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Log an error message
|
|
81
|
-
*
|
|
82
|
-
* @param message - The message to log
|
|
83
|
-
* @param args - Additional arguments to log
|
|
84
|
-
*/
|
|
85
|
-
error(message: unknown, ...args: unknown[]): void {
|
|
86
|
-
try {
|
|
87
|
-
const formattedMessage = formatMessage(this.formatContext, this.context, message, args);
|
|
88
|
-
__originalConsole.error(`${red}[ERROR]${reset} ${formattedMessage}`);
|
|
89
|
-
} catch (err) {
|
|
90
|
-
// Fallback to direct logging if formatting fails
|
|
91
|
-
__originalConsole.error(`${red}[ERROR]${reset} ${message}`, ...args);
|
|
92
|
-
__originalConsole.error('Error formatting log message:', err);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Create a child logger with additional context
|
|
98
|
-
*
|
|
99
|
-
* @param opts - Additional context for the child logger
|
|
100
|
-
* @returns A new logger instance with the additional context
|
|
101
|
-
*/
|
|
102
|
-
child(opts: Record<string, unknown>): Logger {
|
|
103
|
-
return new ConsoleLogger(
|
|
104
|
-
{
|
|
105
|
-
...this.context,
|
|
106
|
-
...opts,
|
|
107
|
-
},
|
|
108
|
-
this.formatContext
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
}
|
package/src/logger/index.ts
DELETED