@fevex/core 0.1.0-alpha.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.
- package/README.md +245 -0
- package/dist/agents/index.d.mts +23 -0
- package/dist/agents/index.mjs +6 -0
- package/dist/exact-definition-NHBBFlFR.d.mts +4 -0
- package/dist/index-D_RBJmVt.d.mts +44 -0
- package/dist/index.d.mts +18 -0
- package/dist/index.mjs +273 -0
- package/dist/models/index.d.mts +27 -0
- package/dist/models/index.mjs +1 -0
- package/dist/runtime/index.d.mts +17 -0
- package/dist/runtime/index.mjs +1 -0
- package/dist/testing/index.d.mts +16 -0
- package/dist/testing/index.mjs +76 -0
- package/dist/tools/index.d.mts +31 -0
- package/dist/tools/index.mjs +13 -0
- package/package.json +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# Fevex
|
|
2
|
+
|
|
3
|
+
Agent Engineering Framework for code-first, provider-neutral AI agents in
|
|
4
|
+
TypeScript.
|
|
5
|
+
|
|
6
|
+
Fevex gives you the small contracts needed to define agents, tools, model
|
|
7
|
+
adapters, validation and tests without adopting a heavy runtime.
|
|
8
|
+
|
|
9
|
+
> **Status:** early MVP. Fevex is usable for local, single-tool agent runs, but
|
|
10
|
+
> its API may change before the first stable release.
|
|
11
|
+
|
|
12
|
+
## Why Fevex
|
|
13
|
+
|
|
14
|
+
- **Provider-neutral:** application code depends on `ModelGateway`, not a model
|
|
15
|
+
vendor SDK.
|
|
16
|
+
- **Typed tools:** Standard Schema validators infer inputs and validate every
|
|
17
|
+
runtime boundary.
|
|
18
|
+
- **Small runtime:** one package, ESM, Node.js 20+, no database or service
|
|
19
|
+
required.
|
|
20
|
+
- **Observable:** successful and failed runs emit structured events.
|
|
21
|
+
- **Testable:** `fevex/testing` includes a deterministic model and shared model
|
|
22
|
+
contract checks.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install fevex
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
For official model adapters:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install fevex @fevex/openai
|
|
34
|
+
npm install fevex @fevex/deepseek
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Schemas are optional. The examples use Zod 4, but any Standard
|
|
38
|
+
Schema-compatible validator can be used:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install zod
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quickstart
|
|
45
|
+
|
|
46
|
+
This example executes a complete model-tool-model cycle without network access:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { createFevex, defineAgent, defineTool } from 'fevex';
|
|
50
|
+
import { fakeModel } from 'fevex/testing';
|
|
51
|
+
import { z } from 'zod';
|
|
52
|
+
|
|
53
|
+
const accountInput = z.object({
|
|
54
|
+
accountId: z.number(),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const accountOutput = z.object({
|
|
58
|
+
accountId: z.number(),
|
|
59
|
+
status: z.literal('active'),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const getAccount = defineTool({
|
|
63
|
+
name: 'accounts.get',
|
|
64
|
+
description: 'Get an account by ID.',
|
|
65
|
+
inputSchema: accountInput,
|
|
66
|
+
outputSchema: accountOutput,
|
|
67
|
+
execute({ accountId }) {
|
|
68
|
+
return { accountId, status: 'active' };
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const model = fakeModel(
|
|
73
|
+
{
|
|
74
|
+
toolCalls: [{
|
|
75
|
+
id: 'call-1',
|
|
76
|
+
name: 'accounts.get',
|
|
77
|
+
input: { accountId: 42 },
|
|
78
|
+
}],
|
|
79
|
+
},
|
|
80
|
+
{ output: 'Account 42 is active.' },
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const app = createFevex({
|
|
84
|
+
models: { default: model },
|
|
85
|
+
agents: [defineAgent({
|
|
86
|
+
name: 'support',
|
|
87
|
+
instructions: 'Answer account questions clearly.',
|
|
88
|
+
tools: ['accounts.get'],
|
|
89
|
+
outputSchema: z.string(),
|
|
90
|
+
})],
|
|
91
|
+
tools: [getAccount],
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const result = await app.runAgent<string, string>('support', {
|
|
95
|
+
input: 'What is the status of account 42?',
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
console.log(result.output);
|
|
99
|
+
// Account 42 is active.
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`fakeModel` returns its configured responses in order and records every input in
|
|
103
|
+
`model.calls`.
|
|
104
|
+
|
|
105
|
+
## Connect A Model
|
|
106
|
+
|
|
107
|
+
Real providers connect through the small `ModelGateway` contract:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import type { ModelGateway } from 'fevex/models';
|
|
111
|
+
|
|
112
|
+
export const model: ModelGateway = {
|
|
113
|
+
async generate({ messages, tools, outputSchema, signal }) {
|
|
114
|
+
const response = await yourProvider.generate({
|
|
115
|
+
messages,
|
|
116
|
+
tools,
|
|
117
|
+
outputSchema,
|
|
118
|
+
signal,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
output: response.output,
|
|
123
|
+
toolCalls: response.toolCalls,
|
|
124
|
+
usage: response.usage,
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Provider integrations remain outside the core package. The first official
|
|
131
|
+
adapter is `@fevex/openai`, authored by Fevex over the native OpenAI HTTP API:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { createOpenAI } from '@fevex/openai';
|
|
135
|
+
|
|
136
|
+
const model = createOpenAI({
|
|
137
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
138
|
+
organization: process.env.OPENAI_ORG_ID,
|
|
139
|
+
project: process.env.OPENAI_PROJECT_ID,
|
|
140
|
+
})('gpt-5.6');
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
DeepSeek follows the same shape:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { createDeepSeek } from '@fevex/deepseek';
|
|
147
|
+
|
|
148
|
+
const model = createDeepSeek({
|
|
149
|
+
apiKey: process.env.DEEPSEEK_API_KEY!,
|
|
150
|
+
})('deepseek-chat');
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Applications can still implement `ModelGateway` directly as shown above.
|
|
154
|
+
|
|
155
|
+
## Validation
|
|
156
|
+
|
|
157
|
+
Fevex accepts
|
|
158
|
+
[`StandardSchemaV1`](https://github.com/standard-schema/standard-schema)
|
|
159
|
+
validators for:
|
|
160
|
+
|
|
161
|
+
- tool input before `execute`;
|
|
162
|
+
- tool output before it is returned to the model;
|
|
163
|
+
- final agent output before it is returned to the application.
|
|
164
|
+
|
|
165
|
+
Schemas may transform values. The transformed result must still be JSON-safe.
|
|
166
|
+
The schema passed to `runAgent` takes precedence over the agent schema for that
|
|
167
|
+
run. Plain JSON Schema objects are not executable validators and are not
|
|
168
|
+
accepted by these fields.
|
|
169
|
+
|
|
170
|
+
When a model adapter needs schemas, Fevex converts authoring schemas that also
|
|
171
|
+
implement Standard JSON Schema into JSON Schema 2020-12 before calling
|
|
172
|
+
`ModelGateway.generate`. Adapters receive transportable JSON Schema in
|
|
173
|
+
`ToolSpec.inputSchema` and `ModelGenerateInput.outputSchema`; they never receive
|
|
174
|
+
the application's executable validators. If a run needs a schema at the model
|
|
175
|
+
boundary and the schema cannot be converted, Fevex fails before invoking the
|
|
176
|
+
model with `SCHEMA_NOT_TRANSPORTABLE`.
|
|
177
|
+
|
|
178
|
+
Use `testModelGateway` to verify a custom model adapter against the shared
|
|
179
|
+
contract:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { testModelGateway } from 'fevex/testing';
|
|
183
|
+
|
|
184
|
+
await testModelGateway(model);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Events
|
|
188
|
+
|
|
189
|
+
Pass `onEvent` to observe success and failure without wrapping provider or tool
|
|
190
|
+
errors:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
const app = createFevex({
|
|
194
|
+
models,
|
|
195
|
+
agents,
|
|
196
|
+
tools,
|
|
197
|
+
onEvent(event) {
|
|
198
|
+
console.log(event.type, event.runId, event.payload);
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The MVP emits:
|
|
204
|
+
|
|
205
|
+
```text
|
|
206
|
+
run.started
|
|
207
|
+
model.completed
|
|
208
|
+
tool.completed
|
|
209
|
+
tool.failed
|
|
210
|
+
run.completed
|
|
211
|
+
run.failed
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Successful runs also return their events in `RunResult.events`.
|
|
215
|
+
|
|
216
|
+
## Public Exports
|
|
217
|
+
|
|
218
|
+
| Import | Purpose |
|
|
219
|
+
| --- | --- |
|
|
220
|
+
| `fevex` | Common runtime, definitions and contracts |
|
|
221
|
+
| `fevex/agents` | Agent definitions |
|
|
222
|
+
| `fevex/models` | Provider-neutral model contracts |
|
|
223
|
+
| `fevex/tools` | Tool definitions and execution context |
|
|
224
|
+
| `fevex/runtime` | Run request and result contracts |
|
|
225
|
+
| `fevex/testing` | Deterministic testing helpers |
|
|
226
|
+
|
|
227
|
+
All subpaths ship in the same `fevex` package.
|
|
228
|
+
|
|
229
|
+
## Current Scope
|
|
230
|
+
|
|
231
|
+
The MVP intentionally supports:
|
|
232
|
+
|
|
233
|
+
- one model response, or one model-tool-model cycle;
|
|
234
|
+
- an in-memory runtime;
|
|
235
|
+
- synchronous event observers;
|
|
236
|
+
- optional Standard Schema validation;
|
|
237
|
+
- `AbortSignal` cancellation.
|
|
238
|
+
|
|
239
|
+
It does not yet include streaming, retries, persistence, approvals, a CLI or
|
|
240
|
+
official provider adapters. `AgentDefinition.limits` is reserved and has no
|
|
241
|
+
runtime effect yet.
|
|
242
|
+
|
|
243
|
+
## License
|
|
244
|
+
|
|
245
|
+
Apache-2.0
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { t as ExactDefinition } from "../exact-definition-NHBBFlFR.mjs";
|
|
2
|
+
import { ModelRef, ReasoningEffort } from "../models/index.mjs";
|
|
3
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
4
|
+
//#region src/agents/index.d.ts
|
|
5
|
+
interface AgentLimits {
|
|
6
|
+
maxSteps?: number;
|
|
7
|
+
maxToolCalls?: number;
|
|
8
|
+
maxInputTokens?: number | false;
|
|
9
|
+
maxOutputTokens?: number | false;
|
|
10
|
+
}
|
|
11
|
+
interface AgentDefinition<TOutput = unknown> {
|
|
12
|
+
name: string;
|
|
13
|
+
instructions: string;
|
|
14
|
+
model?: ModelRef;
|
|
15
|
+
tools?: string[];
|
|
16
|
+
reasoning?: ReasoningEffort;
|
|
17
|
+
modelOptions?: Record<string, unknown>;
|
|
18
|
+
outputSchema?: StandardSchemaV1<unknown, TOutput>;
|
|
19
|
+
limits?: AgentLimits;
|
|
20
|
+
}
|
|
21
|
+
declare function defineAgent<T extends AgentDefinition>(agent: ExactDefinition<T, AgentDefinition>): T;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { AgentDefinition, AgentLimits, defineAgent };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/core/index.d.ts
|
|
2
|
+
type JsonPrimitive = string | number | boolean | null;
|
|
3
|
+
type JsonObject = {
|
|
4
|
+
[key: string]: JsonValue;
|
|
5
|
+
};
|
|
6
|
+
type JsonValue = JsonPrimitive | JsonValue[] | JsonObject;
|
|
7
|
+
type RunId = string;
|
|
8
|
+
declare const SCHEMA_NOT_TRANSPORTABLE = "SCHEMA_NOT_TRANSPORTABLE";
|
|
9
|
+
interface ExecutionContext {
|
|
10
|
+
namespace?: string;
|
|
11
|
+
actor?: {
|
|
12
|
+
id: string;
|
|
13
|
+
type?: string;
|
|
14
|
+
};
|
|
15
|
+
attributes?: JsonObject;
|
|
16
|
+
prompt?: JsonObject;
|
|
17
|
+
}
|
|
18
|
+
type AgentMessageRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
19
|
+
interface AgentMessage {
|
|
20
|
+
role: AgentMessageRole;
|
|
21
|
+
content: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
toolCallId?: string;
|
|
24
|
+
toolCalls?: ToolCall[];
|
|
25
|
+
}
|
|
26
|
+
interface ToolSpec {
|
|
27
|
+
name: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
inputSchema?: JsonObject;
|
|
30
|
+
}
|
|
31
|
+
interface ToolCall {
|
|
32
|
+
id: string;
|
|
33
|
+
name: string;
|
|
34
|
+
input: JsonValue;
|
|
35
|
+
}
|
|
36
|
+
type AgentEventType = 'run.started' | 'model.completed' | 'tool.completed' | 'tool.failed' | 'run.completed' | 'run.failed';
|
|
37
|
+
interface AgentEvent<TPayload extends JsonValue = JsonObject> {
|
|
38
|
+
type: AgentEventType;
|
|
39
|
+
runId: RunId;
|
|
40
|
+
timestamp: string;
|
|
41
|
+
payload?: TPayload;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { ExecutionContext as a, JsonValue as c, ToolCall as d, ToolSpec as f, AgentMessageRole as i, RunId as l, AgentEventType as n, JsonObject as o, AgentMessage as r, JsonPrimitive as s, AgentEvent as t, SCHEMA_NOT_TRANSPORTABLE as u };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { a as ExecutionContext, c as JsonValue, d as ToolCall, f as ToolSpec, i as AgentMessageRole, l as RunId, n as AgentEventType, o as JsonObject, r as AgentMessage, s as JsonPrimitive, t as AgentEvent, u as SCHEMA_NOT_TRANSPORTABLE } from "./index-D_RBJmVt.mjs";
|
|
2
|
+
import { ModelGateway, ModelGenerateInput, ModelGenerateResult, ModelRef, ModelUsage, ReasoningEffort } from "./models/index.mjs";
|
|
3
|
+
import { AgentDefinition, AgentLimits, defineAgent } from "./agents/index.mjs";
|
|
4
|
+
import { RunRequest, RunResult } from "./runtime/index.mjs";
|
|
5
|
+
import { ToolDefinition, ToolExecutionContext, ToolResult, defineTool, toToolSpec } from "./tools/index.mjs";
|
|
6
|
+
//#region src/index.d.ts
|
|
7
|
+
interface FevexConfig {
|
|
8
|
+
models: Record<string, ModelGateway>;
|
|
9
|
+
agents: AgentDefinition[];
|
|
10
|
+
tools?: ToolDefinition[];
|
|
11
|
+
onEvent?: (event: AgentEvent) => void;
|
|
12
|
+
}
|
|
13
|
+
interface Fevex {
|
|
14
|
+
runAgent<TInput = unknown, TOutput = unknown>(name: string, request: RunRequest<TInput, TOutput>): Promise<RunResult<TOutput>>;
|
|
15
|
+
}
|
|
16
|
+
declare function createFevex(config: FevexConfig): Fevex;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { AgentDefinition, AgentEvent, AgentEventType, AgentLimits, AgentMessage, AgentMessageRole, ExecutionContext, Fevex, FevexConfig, JsonObject, JsonPrimitive, JsonValue, ModelGateway, ModelGenerateInput, ModelGenerateResult, ModelRef, ModelUsage, ReasoningEffort, RunId, RunRequest, RunResult, SCHEMA_NOT_TRANSPORTABLE, ToolCall, ToolDefinition, ToolExecutionContext, ToolResult, ToolSpec, createFevex, defineAgent, defineTool, toToolSpec };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { defineTool, toToolSpec } from "./tools/index.mjs";
|
|
2
|
+
import { defineAgent } from "./agents/index.mjs";
|
|
3
|
+
import "./models/index.mjs";
|
|
4
|
+
import "./runtime/index.mjs";
|
|
5
|
+
//#region src/core/index.ts
|
|
6
|
+
const SCHEMA_NOT_TRANSPORTABLE = "SCHEMA_NOT_TRANSPORTABLE";
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/index.ts
|
|
9
|
+
const invalidJsonValue = Symbol("invalid-json-value");
|
|
10
|
+
function normalizeJsonValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
11
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return value;
|
|
12
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : invalidJsonValue;
|
|
13
|
+
if (Array.isArray(value)) {
|
|
14
|
+
const normalized = [];
|
|
15
|
+
for (const item of value) {
|
|
16
|
+
const normalizedItem = normalizeJsonValue(item, seen);
|
|
17
|
+
if (normalizedItem === invalidJsonValue) return invalidJsonValue;
|
|
18
|
+
normalized.push(normalizedItem);
|
|
19
|
+
}
|
|
20
|
+
return normalized;
|
|
21
|
+
}
|
|
22
|
+
if (typeof value !== "object" || value === void 0) return invalidJsonValue;
|
|
23
|
+
const prototype = Object.getPrototypeOf(value);
|
|
24
|
+
if (prototype !== null && prototype !== Object.prototype) return invalidJsonValue;
|
|
25
|
+
if (seen.has(value)) return invalidJsonValue;
|
|
26
|
+
seen.add(value);
|
|
27
|
+
const normalized = {};
|
|
28
|
+
for (const [key, item] of Object.entries(value)) {
|
|
29
|
+
if (item === void 0) continue;
|
|
30
|
+
const normalizedItem = normalizeJsonValue(item, seen);
|
|
31
|
+
if (normalizedItem === invalidJsonValue) return invalidJsonValue;
|
|
32
|
+
normalized[key] = normalizedItem;
|
|
33
|
+
}
|
|
34
|
+
seen.delete(value);
|
|
35
|
+
return normalized;
|
|
36
|
+
}
|
|
37
|
+
function toJsonValue(value, errorMessage) {
|
|
38
|
+
let normalized;
|
|
39
|
+
try {
|
|
40
|
+
normalized = normalizeJsonValue(value);
|
|
41
|
+
} catch {
|
|
42
|
+
throw new TypeError(errorMessage);
|
|
43
|
+
}
|
|
44
|
+
if (normalized === invalidJsonValue) throw new TypeError(errorMessage);
|
|
45
|
+
return normalized;
|
|
46
|
+
}
|
|
47
|
+
function serializeJsonValue(value) {
|
|
48
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
49
|
+
}
|
|
50
|
+
function serializeValue(value, errorMessage) {
|
|
51
|
+
return serializeJsonValue(toJsonValue(value, errorMessage));
|
|
52
|
+
}
|
|
53
|
+
function isStandardSchema(value) {
|
|
54
|
+
if (typeof value !== "object" || value === null || !("~standard" in value)) return false;
|
|
55
|
+
const standard = value["~standard"];
|
|
56
|
+
return typeof standard === "object" && standard !== null && standard.version === 1 && typeof standard.validate === "function";
|
|
57
|
+
}
|
|
58
|
+
function assertStandardSchema(value, errorMessage) {
|
|
59
|
+
if (!isStandardSchema(value)) throw new TypeError(errorMessage);
|
|
60
|
+
}
|
|
61
|
+
function isStandardJsonSchema(value) {
|
|
62
|
+
if (!isStandardSchema(value)) return false;
|
|
63
|
+
const jsonSchema = value["~standard"].jsonSchema;
|
|
64
|
+
return typeof jsonSchema === "object" && jsonSchema !== null && typeof jsonSchema.input === "function" && typeof jsonSchema.output === "function";
|
|
65
|
+
}
|
|
66
|
+
function schemaNotTransportable(message) {
|
|
67
|
+
return Object.assign(new TypeError(message), { code: SCHEMA_NOT_TRANSPORTABLE });
|
|
68
|
+
}
|
|
69
|
+
function toTransportableSchema(schema, direction, errorMessage) {
|
|
70
|
+
if (!isStandardJsonSchema(schema)) throw schemaNotTransportable(`${errorMessage}: schema does not implement Standard JSON Schema`);
|
|
71
|
+
let rawSchema;
|
|
72
|
+
try {
|
|
73
|
+
rawSchema = schema["~standard"].jsonSchema[direction]({ target: "draft-2020-12" });
|
|
74
|
+
} catch (error) {
|
|
75
|
+
throw schemaNotTransportable(`${errorMessage}: ${toErrorMessage(error)}`);
|
|
76
|
+
}
|
|
77
|
+
let jsonSchema;
|
|
78
|
+
try {
|
|
79
|
+
jsonSchema = toJsonValue(rawSchema, `${errorMessage}: JSON Schema must be JSON-serializable`);
|
|
80
|
+
} catch {
|
|
81
|
+
throw schemaNotTransportable(`${errorMessage}: JSON Schema must be JSON-serializable`);
|
|
82
|
+
}
|
|
83
|
+
if (typeof jsonSchema !== "object" || jsonSchema === null || Array.isArray(jsonSchema)) throw schemaNotTransportable(`${errorMessage}: JSON Schema must be an object`);
|
|
84
|
+
return jsonSchema;
|
|
85
|
+
}
|
|
86
|
+
async function validateSchema(schema, value, errorMessage) {
|
|
87
|
+
const result = await schema["~standard"].validate(value);
|
|
88
|
+
if (result.issues) {
|
|
89
|
+
const detail = result.issues[0]?.message ?? "Validation failed";
|
|
90
|
+
throw new TypeError(`${errorMessage}: ${detail}`);
|
|
91
|
+
}
|
|
92
|
+
return result.value;
|
|
93
|
+
}
|
|
94
|
+
function toErrorMessage(error) {
|
|
95
|
+
if (error instanceof Error) return error.message;
|
|
96
|
+
if (typeof error === "string") return error;
|
|
97
|
+
try {
|
|
98
|
+
return JSON.stringify(error) ?? String(error);
|
|
99
|
+
} catch {
|
|
100
|
+
return String(error);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function addUsage(first, second) {
|
|
104
|
+
if (!first) return second;
|
|
105
|
+
if (!second) return first;
|
|
106
|
+
const inputTokens = first.inputTokens === void 0 && second.inputTokens === void 0 ? void 0 : (first.inputTokens ?? 0) + (second.inputTokens ?? 0);
|
|
107
|
+
const outputTokens = first.outputTokens === void 0 && second.outputTokens === void 0 ? void 0 : (first.outputTokens ?? 0) + (second.outputTokens ?? 0);
|
|
108
|
+
const totalTokens = first.totalTokens === void 0 && second.totalTokens === void 0 ? void 0 : (first.totalTokens ?? 0) + (second.totalTokens ?? 0);
|
|
109
|
+
return {
|
|
110
|
+
...inputTokens !== void 0 ? { inputTokens } : {},
|
|
111
|
+
...outputTokens !== void 0 ? { outputTokens } : {},
|
|
112
|
+
...totalTokens !== void 0 ? { totalTokens } : {}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function createFevex(config) {
|
|
116
|
+
const models = new Map(Object.entries(config.models));
|
|
117
|
+
const agents = /* @__PURE__ */ new Map();
|
|
118
|
+
const tools = /* @__PURE__ */ new Map();
|
|
119
|
+
for (const [name, model] of models) {
|
|
120
|
+
if (!name.trim()) throw new Error("Model name cannot be empty");
|
|
121
|
+
if (!model || typeof model.generate !== "function") throw new Error(`Model "${name}" must implement generate`);
|
|
122
|
+
}
|
|
123
|
+
for (const tool of config.tools ?? []) {
|
|
124
|
+
if (!tool.name.trim()) throw new Error("Tool name cannot be empty");
|
|
125
|
+
if (tools.has(tool.name)) throw new Error(`Tool "${tool.name}" is duplicated`);
|
|
126
|
+
if (tool.inputSchema !== void 0) assertStandardSchema(tool.inputSchema, `Input schema for tool "${tool.name}" must implement Standard Schema`);
|
|
127
|
+
if (tool.outputSchema !== void 0) assertStandardSchema(tool.outputSchema, `Output schema for tool "${tool.name}" must implement Standard Schema`);
|
|
128
|
+
tools.set(tool.name, tool);
|
|
129
|
+
}
|
|
130
|
+
for (const agent of config.agents) {
|
|
131
|
+
if (!agent.name.trim()) throw new Error("Agent name cannot be empty");
|
|
132
|
+
if (!agent.instructions.trim()) throw new Error(`Agent "${agent.name}" instructions cannot be empty`);
|
|
133
|
+
if (agents.has(agent.name)) throw new Error(`Agent "${agent.name}" is duplicated`);
|
|
134
|
+
if (agent.outputSchema !== void 0) assertStandardSchema(agent.outputSchema, `Output schema for agent "${agent.name}" must implement Standard Schema`);
|
|
135
|
+
agents.set(agent.name, agent);
|
|
136
|
+
}
|
|
137
|
+
for (const agent of agents.values()) {
|
|
138
|
+
if (typeof agent.model === "string" && !models.has(agent.model)) throw new Error(`Model "${agent.model}" required by agent "${agent.name}" is not registered`);
|
|
139
|
+
if (agent.model && typeof agent.model !== "string" && typeof agent.model.generate !== "function") throw new Error(`Model for agent "${agent.name}" must implement generate`);
|
|
140
|
+
if (!agent.model && !models.has("default")) throw new Error(`Default model "default" required by agent "${agent.name}" is not registered`);
|
|
141
|
+
for (const toolName of agent.tools ?? []) if (!tools.has(toolName)) throw new Error(`Tool "${toolName}" required by agent "${agent.name}" is not registered`);
|
|
142
|
+
}
|
|
143
|
+
return { async runAgent(name, request) {
|
|
144
|
+
const agent = agents.get(name);
|
|
145
|
+
if (!agent) throw new Error(`Agent "${name}" is not registered`);
|
|
146
|
+
const model = typeof agent.model === "string" ? models.get(agent.model) : agent.model ?? models.get("default");
|
|
147
|
+
const runId = globalThis.crypto.randomUUID();
|
|
148
|
+
const events = [];
|
|
149
|
+
const createEvent = (type, payload) => ({
|
|
150
|
+
type,
|
|
151
|
+
runId,
|
|
152
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
153
|
+
...payload === void 0 ? {} : { payload }
|
|
154
|
+
});
|
|
155
|
+
const emit = (type, payload) => {
|
|
156
|
+
const event = createEvent(type, payload);
|
|
157
|
+
config.onEvent?.(event);
|
|
158
|
+
events.push(event);
|
|
159
|
+
};
|
|
160
|
+
const emitFailure = (type, payload) => {
|
|
161
|
+
const event = createEvent(type, payload);
|
|
162
|
+
try {
|
|
163
|
+
config.onEvent?.(event);
|
|
164
|
+
} catch {}
|
|
165
|
+
events.push(event);
|
|
166
|
+
};
|
|
167
|
+
try {
|
|
168
|
+
emit("run.started");
|
|
169
|
+
request.signal?.throwIfAborted();
|
|
170
|
+
if (request.outputSchema !== void 0) assertStandardSchema(request.outputSchema, `Output schema for request to agent "${name}" must implement Standard Schema`);
|
|
171
|
+
const messages = [{
|
|
172
|
+
role: "system",
|
|
173
|
+
content: agent.instructions
|
|
174
|
+
}, {
|
|
175
|
+
role: "user",
|
|
176
|
+
content: serializeValue(request.input, "Run input must be a string or JSON-serializable value")
|
|
177
|
+
}];
|
|
178
|
+
const activeOutputSchema = request.outputSchema !== void 0 ? request.outputSchema : agent.outputSchema;
|
|
179
|
+
const outputSchema = activeOutputSchema === void 0 ? void 0 : toTransportableSchema(activeOutputSchema, "output", `Output schema for agent "${name}" is not transportable`);
|
|
180
|
+
const agentTools = (agent.tools ?? []).map((toolName) => {
|
|
181
|
+
const tool = tools.get(toolName);
|
|
182
|
+
return toToolSpec(tool, tool.inputSchema === void 0 ? void 0 : toTransportableSchema(tool.inputSchema, "input", `Input schema for tool "${tool.name}" is not transportable`));
|
|
183
|
+
});
|
|
184
|
+
const result = await model.generate({
|
|
185
|
+
messages,
|
|
186
|
+
tools: agentTools.length > 0 ? agentTools : void 0,
|
|
187
|
+
reasoning: agent.reasoning,
|
|
188
|
+
modelOptions: agent.modelOptions,
|
|
189
|
+
outputSchema,
|
|
190
|
+
signal: request.signal
|
|
191
|
+
});
|
|
192
|
+
emit("model.completed");
|
|
193
|
+
if (!result.toolCalls?.length) {
|
|
194
|
+
if (result.output === void 0) throw new Error(`Model for agent "${name}" returned no output`);
|
|
195
|
+
const output = toJsonValue(activeOutputSchema === void 0 ? result.output : await validateSchema(activeOutputSchema, result.output, `Output from agent "${name}" does not match outputSchema`), `Output from agent "${name}" must be JSON-serializable`);
|
|
196
|
+
emit("run.completed");
|
|
197
|
+
return {
|
|
198
|
+
output,
|
|
199
|
+
events,
|
|
200
|
+
usage: result.usage
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (result.toolCalls.length > 1) throw new Error(`Agent "${name}" requested multiple tools, but this runtime supports one tool call`);
|
|
204
|
+
const toolCall = result.toolCalls[0];
|
|
205
|
+
if (typeof toolCall.id !== "string" || !toolCall.id.trim()) throw new Error("Tool call id cannot be empty");
|
|
206
|
+
if (typeof toolCall.name !== "string" || !toolCall.name.trim()) throw new Error("Tool call name cannot be empty");
|
|
207
|
+
const assistantContent = result.output === void 0 ? "" : serializeValue(result.output, `Model output for agent "${name}" must be JSON-serializable`);
|
|
208
|
+
request.signal?.throwIfAborted();
|
|
209
|
+
let toolContent;
|
|
210
|
+
try {
|
|
211
|
+
const tool = agent.tools?.includes(toolCall.name) ? tools.get(toolCall.name) : void 0;
|
|
212
|
+
if (!tool) throw new Error(`Tool "${toolCall.name}" is not available to agent "${name}"`);
|
|
213
|
+
const rawToolInput = toJsonValue(toolCall.input, `Input for tool "${toolCall.name}" must be JSON-serializable`);
|
|
214
|
+
const toolInput = toJsonValue(tool.inputSchema === void 0 ? rawToolInput : await validateSchema(tool.inputSchema, rawToolInput, `Input for tool "${toolCall.name}" does not match inputSchema`), `Input for tool "${toolCall.name}" must be JSON-serializable`);
|
|
215
|
+
const rawToolOutput = await tool.execute(toolInput, {
|
|
216
|
+
runId,
|
|
217
|
+
toolCallId: toolCall.id,
|
|
218
|
+
context: request.context,
|
|
219
|
+
signal: request.signal
|
|
220
|
+
});
|
|
221
|
+
toolContent = serializeJsonValue(toJsonValue(tool.outputSchema === void 0 ? rawToolOutput : await validateSchema(tool.outputSchema, rawToolOutput, `Output from tool "${toolCall.name}" does not match outputSchema`), `Output from tool "${toolCall.name}" must be JSON-serializable`));
|
|
222
|
+
} catch (error) {
|
|
223
|
+
emitFailure("tool.failed", {
|
|
224
|
+
toolCallId: toolCall.id,
|
|
225
|
+
toolName: toolCall.name,
|
|
226
|
+
error: toErrorMessage(error)
|
|
227
|
+
});
|
|
228
|
+
throw error;
|
|
229
|
+
}
|
|
230
|
+
emit("tool.completed", {
|
|
231
|
+
toolCallId: toolCall.id,
|
|
232
|
+
toolName: toolCall.name
|
|
233
|
+
});
|
|
234
|
+
request.signal?.throwIfAborted();
|
|
235
|
+
const finalResult = await model.generate({
|
|
236
|
+
messages: [
|
|
237
|
+
...messages,
|
|
238
|
+
{
|
|
239
|
+
role: "assistant",
|
|
240
|
+
content: assistantContent,
|
|
241
|
+
toolCalls: [toolCall]
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
role: "tool",
|
|
245
|
+
name: toolCall.name,
|
|
246
|
+
toolCallId: toolCall.id,
|
|
247
|
+
content: toolContent
|
|
248
|
+
}
|
|
249
|
+
],
|
|
250
|
+
tools: void 0,
|
|
251
|
+
reasoning: agent.reasoning,
|
|
252
|
+
modelOptions: agent.modelOptions,
|
|
253
|
+
outputSchema,
|
|
254
|
+
signal: request.signal
|
|
255
|
+
});
|
|
256
|
+
emit("model.completed");
|
|
257
|
+
if (finalResult.toolCalls?.length) throw new Error(`Agent "${name}" requested another tool, but this runtime supports one tool call`);
|
|
258
|
+
if (finalResult.output === void 0) throw new Error(`Model for agent "${name}" returned no output`);
|
|
259
|
+
const output = toJsonValue(activeOutputSchema === void 0 ? finalResult.output : await validateSchema(activeOutputSchema, finalResult.output, `Output from agent "${name}" does not match outputSchema`), `Output from agent "${name}" must be JSON-serializable`);
|
|
260
|
+
emit("run.completed");
|
|
261
|
+
return {
|
|
262
|
+
output,
|
|
263
|
+
events,
|
|
264
|
+
usage: addUsage(result.usage, finalResult.usage)
|
|
265
|
+
};
|
|
266
|
+
} catch (error) {
|
|
267
|
+
emitFailure("run.failed", { error: toErrorMessage(error) });
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
} };
|
|
271
|
+
}
|
|
272
|
+
//#endregion
|
|
273
|
+
export { SCHEMA_NOT_TRANSPORTABLE, createFevex, defineAgent, defineTool, toToolSpec };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { d as ToolCall, f as ToolSpec, o as JsonObject, r as AgentMessage } from "../index-D_RBJmVt.mjs";
|
|
2
|
+
//#region src/models/index.d.ts
|
|
3
|
+
type ReasoningEffort = 'provider-default' | 'none' | 'minimal' | 'low' | 'medium' | 'high';
|
|
4
|
+
interface ModelUsage {
|
|
5
|
+
inputTokens?: number;
|
|
6
|
+
outputTokens?: number;
|
|
7
|
+
totalTokens?: number;
|
|
8
|
+
}
|
|
9
|
+
interface ModelGenerateInput {
|
|
10
|
+
messages: AgentMessage[];
|
|
11
|
+
tools?: ToolSpec[];
|
|
12
|
+
reasoning?: ReasoningEffort;
|
|
13
|
+
modelOptions?: Record<string, unknown>;
|
|
14
|
+
outputSchema?: JsonObject;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
}
|
|
17
|
+
interface ModelGenerateResult<TOutput = unknown> {
|
|
18
|
+
output?: TOutput;
|
|
19
|
+
toolCalls?: ToolCall[];
|
|
20
|
+
usage?: ModelUsage;
|
|
21
|
+
}
|
|
22
|
+
interface ModelGateway {
|
|
23
|
+
generate(input: ModelGenerateInput): Promise<ModelGenerateResult>;
|
|
24
|
+
}
|
|
25
|
+
type ModelRef = string | ModelGateway;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { ModelGateway, ModelGenerateInput, ModelGenerateResult, ModelRef, ModelUsage, ReasoningEffort };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { a as ExecutionContext, t as AgentEvent } from "../index-D_RBJmVt.mjs";
|
|
2
|
+
import { ModelUsage } from "../models/index.mjs";
|
|
3
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
4
|
+
//#region src/runtime/index.d.ts
|
|
5
|
+
interface RunRequest<TInput = unknown, TOutput = unknown> {
|
|
6
|
+
input: TInput;
|
|
7
|
+
context?: ExecutionContext;
|
|
8
|
+
outputSchema?: StandardSchemaV1<unknown, TOutput>;
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
}
|
|
11
|
+
interface RunResult<TOutput = unknown> {
|
|
12
|
+
output: TOutput;
|
|
13
|
+
events?: AgentEvent[];
|
|
14
|
+
usage?: ModelUsage;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { RunRequest, RunResult };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { d as ToolCall } from "../index-D_RBJmVt.mjs";
|
|
2
|
+
import { ModelGateway, ModelGenerateInput, ModelGenerateResult } from "../models/index.mjs";
|
|
3
|
+
//#region src/testing/index.d.ts
|
|
4
|
+
interface FakeModel extends ModelGateway {
|
|
5
|
+
readonly calls: readonly ModelGenerateInput[];
|
|
6
|
+
}
|
|
7
|
+
declare function fakeModel(...responses: ModelGenerateResult[]): FakeModel;
|
|
8
|
+
interface ModelGatewayContract {
|
|
9
|
+
output?: unknown;
|
|
10
|
+
toolCall?: ToolCall;
|
|
11
|
+
usage?: boolean;
|
|
12
|
+
error?: Error;
|
|
13
|
+
}
|
|
14
|
+
declare function testModelGateway(model: ModelGateway, contract?: ModelGatewayContract): Promise<void>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { FakeModel, ModelGatewayContract, fakeModel, testModelGateway };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//#region src/testing/index.ts
|
|
2
|
+
function fakeModel(...responses) {
|
|
3
|
+
const calls = [];
|
|
4
|
+
return {
|
|
5
|
+
calls,
|
|
6
|
+
async generate(input) {
|
|
7
|
+
input.signal?.throwIfAborted();
|
|
8
|
+
const response = responses[calls.length];
|
|
9
|
+
calls.push(input);
|
|
10
|
+
if (!response) throw new Error(`fakeModel has no response for call ${calls.length}`);
|
|
11
|
+
return response;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const contractOutputSchema = { type: "string" };
|
|
16
|
+
const contractToolInputSchema = {
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: { query: { type: "string" } },
|
|
19
|
+
required: ["query"]
|
|
20
|
+
};
|
|
21
|
+
function assert(condition, message) {
|
|
22
|
+
if (!condition) throw new TypeError(message);
|
|
23
|
+
}
|
|
24
|
+
async function testModelGateway(model, contract = {}) {
|
|
25
|
+
const output = contract.output ?? "ok";
|
|
26
|
+
const toolCall = contract.toolCall ?? {
|
|
27
|
+
id: "call-1",
|
|
28
|
+
name: "lookup",
|
|
29
|
+
input: { query: "value" }
|
|
30
|
+
};
|
|
31
|
+
const outputResult = await model.generate({
|
|
32
|
+
messages: [{
|
|
33
|
+
role: "user",
|
|
34
|
+
content: "Return a final answer."
|
|
35
|
+
}],
|
|
36
|
+
outputSchema: contractOutputSchema
|
|
37
|
+
});
|
|
38
|
+
assert(outputResult.output !== void 0, "ModelGateway must return output for a final answer");
|
|
39
|
+
assert(outputResult.output === output, "ModelGateway returned an unexpected output");
|
|
40
|
+
if (contract.usage) assert(outputResult.usage !== void 0, "ModelGateway must return usage when the contract requires it");
|
|
41
|
+
const toolResult = await model.generate({
|
|
42
|
+
messages: [{
|
|
43
|
+
role: "user",
|
|
44
|
+
content: "Call lookup."
|
|
45
|
+
}],
|
|
46
|
+
tools: [{
|
|
47
|
+
name: "lookup",
|
|
48
|
+
description: "Look up a value.",
|
|
49
|
+
inputSchema: contractToolInputSchema
|
|
50
|
+
}]
|
|
51
|
+
});
|
|
52
|
+
assert(toolResult.toolCalls?.length === 1, "ModelGateway must return one tool call");
|
|
53
|
+
assert(toolResult.toolCalls[0]?.id === toolCall.id, "ModelGateway returned an unexpected tool call id");
|
|
54
|
+
assert(toolResult.toolCalls[0]?.name === toolCall.name, "ModelGateway returned an unexpected tool name");
|
|
55
|
+
const controller = new AbortController();
|
|
56
|
+
controller.abort();
|
|
57
|
+
await model.generate({
|
|
58
|
+
messages: [{
|
|
59
|
+
role: "user",
|
|
60
|
+
content: "This call is aborted."
|
|
61
|
+
}],
|
|
62
|
+
signal: controller.signal
|
|
63
|
+
}).then(() => {
|
|
64
|
+
throw new TypeError("ModelGateway must reject aborted calls");
|
|
65
|
+
}, () => {});
|
|
66
|
+
if (contract.error) await model.generate({ messages: [{
|
|
67
|
+
role: "user",
|
|
68
|
+
content: "Propagate an error."
|
|
69
|
+
}] }).then(() => {
|
|
70
|
+
throw new TypeError("ModelGateway must propagate provider errors");
|
|
71
|
+
}, (error) => {
|
|
72
|
+
assert(error === contract.error, "ModelGateway must preserve provider error identity");
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { fakeModel, testModelGateway };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { t as ExactDefinition } from "../exact-definition-NHBBFlFR.mjs";
|
|
2
|
+
import { a as ExecutionContext, c as JsonValue, d as ToolCall, f as ToolSpec, l as RunId, o as JsonObject } from "../index-D_RBJmVt.mjs";
|
|
3
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
4
|
+
//#region src/tools/index.d.ts
|
|
5
|
+
interface ToolExecutionContext {
|
|
6
|
+
runId: RunId;
|
|
7
|
+
toolCallId: string;
|
|
8
|
+
context?: ExecutionContext;
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
}
|
|
11
|
+
interface ToolDefinition<TInput = unknown, TOutput = unknown> {
|
|
12
|
+
name: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
inputSchema?: StandardSchemaV1<unknown, TInput>;
|
|
15
|
+
outputSchema?: StandardSchemaV1<unknown, TOutput>;
|
|
16
|
+
execute(input: TInput, context: ToolExecutionContext): TOutput | Promise<TOutput>;
|
|
17
|
+
}
|
|
18
|
+
type ToolWithSchemas<TInputSchema extends StandardSchemaV1, TOutputSchema extends StandardSchemaV1> = Omit<ToolDefinition<StandardSchemaV1.InferOutput<TInputSchema>, StandardSchemaV1.InferOutput<TOutputSchema>>, 'inputSchema' | 'outputSchema'> & {
|
|
19
|
+
inputSchema: TInputSchema;
|
|
20
|
+
outputSchema: TOutputSchema;
|
|
21
|
+
};
|
|
22
|
+
type ToolWithInputSchema<TInputSchema extends StandardSchemaV1> = Omit<ToolDefinition<StandardSchemaV1.InferOutput<TInputSchema>, unknown>, 'inputSchema'> & {
|
|
23
|
+
inputSchema: TInputSchema;
|
|
24
|
+
};
|
|
25
|
+
declare function defineTool<TInputSchema extends StandardSchemaV1, TOutputSchema extends StandardSchemaV1, TDefinition extends ToolWithSchemas<TInputSchema, TOutputSchema>>(tool: ToolWithSchemas<TInputSchema, TOutputSchema> & ExactDefinition<TDefinition, ToolWithSchemas<TInputSchema, TOutputSchema>>): TDefinition;
|
|
26
|
+
declare function defineTool<TInputSchema extends StandardSchemaV1, TDefinition extends ToolWithInputSchema<TInputSchema>>(tool: ToolWithInputSchema<TInputSchema> & ExactDefinition<TDefinition, ToolWithInputSchema<TInputSchema>>): TDefinition;
|
|
27
|
+
declare function defineTool<TDefinition extends ToolDefinition>(tool: ToolDefinition & ExactDefinition<TDefinition, ToolDefinition>): TDefinition;
|
|
28
|
+
declare function toToolSpec(tool: ToolDefinition, inputSchema?: JsonObject): ToolSpec;
|
|
29
|
+
type ToolResult = JsonValue;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { type ToolCall, ToolDefinition, ToolExecutionContext, ToolResult, type ToolSpec, defineTool, toToolSpec };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/tools/index.ts
|
|
2
|
+
function defineTool(tool) {
|
|
3
|
+
return tool;
|
|
4
|
+
}
|
|
5
|
+
function toToolSpec(tool, inputSchema) {
|
|
6
|
+
return {
|
|
7
|
+
name: tool.name,
|
|
8
|
+
description: tool.description,
|
|
9
|
+
...inputSchema === void 0 ? {} : { inputSchema }
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { defineTool, toToolSpec };
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fevex/core",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "Agent Engineering Framework for code-first, provider-neutral AI agents.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"main": "./dist/index.mjs",
|
|
8
|
+
"module": "./dist/index.mjs",
|
|
9
|
+
"types": "./dist/index.d.mts",
|
|
10
|
+
"files": ["dist"],
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/hemia-labs/fevex.git",
|
|
15
|
+
"directory": "packages/fevex"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/hemia-labs/fevex/issues"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/hemia-labs/fevex#readme",
|
|
21
|
+
"keywords": ["ai", "agents", "agent-framework", "agent-engineering", "typescript", "fevex"],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20"
|
|
24
|
+
},
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.mts",
|
|
28
|
+
"import": "./dist/index.mjs"
|
|
29
|
+
},
|
|
30
|
+
"./agents": {
|
|
31
|
+
"types": "./dist/agents/index.d.mts",
|
|
32
|
+
"import": "./dist/agents/index.mjs"
|
|
33
|
+
},
|
|
34
|
+
"./models": {
|
|
35
|
+
"types": "./dist/models/index.d.mts",
|
|
36
|
+
"import": "./dist/models/index.mjs"
|
|
37
|
+
},
|
|
38
|
+
"./tools": {
|
|
39
|
+
"types": "./dist/tools/index.d.mts",
|
|
40
|
+
"import": "./dist/tools/index.mjs"
|
|
41
|
+
},
|
|
42
|
+
"./runtime": {
|
|
43
|
+
"types": "./dist/runtime/index.d.mts",
|
|
44
|
+
"import": "./dist/runtime/index.mjs"
|
|
45
|
+
},
|
|
46
|
+
"./testing": {
|
|
47
|
+
"types": "./dist/testing/index.d.mts",
|
|
48
|
+
"import": "./dist/testing/index.mjs"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsdown src/index.ts src/agents/index.ts src/models/index.ts src/tools/index.ts src/runtime/index.ts src/testing/index.ts --format esm --dts",
|
|
53
|
+
"prepack": "bun run build",
|
|
54
|
+
"test": "bun test src/index.test.ts src/testing/index.test.ts",
|
|
55
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
56
|
+
},
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@standard-schema/spec": "^1.1.0"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"typescript": "^5.7.0"
|
|
65
|
+
}
|
|
66
|
+
}
|