@lunora/agent 1.0.0-alpha.9 → 1.0.0-alpha.91
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/dist/channels.d.mts +3 -11
- package/dist/channels.d.ts +3 -11
- package/dist/channels.mjs +1 -181
- package/dist/component.d.mts +2 -0
- package/dist/component.d.ts +2 -0
- package/dist/component.mjs +2 -418
- package/dist/inbound.d.mts +7 -5
- package/dist/inbound.d.ts +7 -5
- package/dist/inbound.mjs +1 -32
- package/dist/index.d.mts +49 -8
- package/dist/index.d.ts +49 -8
- package/dist/index.mjs +1 -18
- package/dist/naming.mjs +1 -8
- package/dist/packem_shared/AGENT_MODULE-M4D1EejI.mjs +1 -0
- package/dist/packem_shared/VoiceSessionDO-BdvnaLoO.mjs +1 -0
- package/dist/packem_shared/adaptMcpResult-CVlq-_TO.mjs +2 -0
- package/dist/packem_shared/agent-loop-B3KTMfqm.mjs +3 -0
- package/dist/packem_shared/agentAsTool-CgZb6ycK.mjs +1 -0
- package/dist/packem_shared/base64-5eyBfWO3.mjs +1 -0
- package/dist/packem_shared/braintrustTelemetry-Byne8uPK.mjs +1 -0
- package/dist/packem_shared/branch-marker-boZ00zmk.mjs +1 -0
- package/dist/packem_shared/buildModelMessages-Y4tGo1T9.mjs +5 -0
- package/dist/packem_shared/codeTool-BQb-K3my.mjs +1 -0
- package/dist/packem_shared/collectAgenticMemoryTools-BeMWT2qt.mjs +1 -0
- package/dist/packem_shared/combineTelemetry-DgE9W9G8.mjs +1 -0
- package/dist/packem_shared/common-CJSjtsfv.mjs +1 -0
- package/dist/packem_shared/compileAgentWorkflow-DRkaF9sV.mjs +1 -0
- package/dist/packem_shared/component-shared-G8ngerkU.mjs +1 -0
- package/dist/packem_shared/consoleTelemetry-BZY3Y-Ly.mjs +1 -0
- package/dist/packem_shared/createAgentContext-DPFZ88dr.mjs +1 -0
- package/dist/packem_shared/createAgentGenerate-BOILDUZj.mjs +3 -0
- package/dist/packem_shared/createDispatchRunner-BMgSkFiH-DjUQx8vg.mjs +1 -0
- package/dist/packem_shared/defineAgent-Q3MlQjYs.mjs +3 -0
- package/dist/packem_shared/defineSkill-DGGvDWNq.mjs +1 -0
- package/dist/packem_shared/fnv1a-BNN96GYb.mjs +1 -0
- package/dist/packem_shared/functionTool-D3CP4f8-.mjs +1 -0
- package/dist/packem_shared/in-flight-calls-GH1A_1P3.mjs +1 -0
- package/dist/packem_shared/normalizeEntityName-k3fjicAG.mjs +2 -0
- package/dist/packem_shared/otlpTelemetry-ByqrB-72.mjs +1 -0
- package/dist/packem_shared/positive-integer-ztHqqpBk.mjs +1 -0
- package/dist/packem_shared/runAgentLoop-DJvzWDgh.mjs +1 -0
- package/dist/packem_shared/runVoiceTurn-D1WCjVPw.mjs +1 -0
- package/dist/packem_shared/sandboxComponent-BtOkUYpY.mjs +5 -0
- package/dist/packem_shared/sentryTelemetry-BHeydiAB.mjs +1 -0
- package/dist/packem_shared/tool-output-Cmk3JWMG.mjs +1 -0
- package/dist/packem_shared/{types.d-boAM2Yi1.d.mts → types.d-B8WZl1rU.d.mts} +255 -22
- package/dist/packem_shared/{types.d-boAM2Yi1.d.ts → types.d-B8WZl1rU.d.ts} +255 -22
- package/dist/packem_shared/voice-turn-D1ZzTzcE.mjs +1 -0
- package/dist/reply.d.mts +40 -0
- package/dist/reply.d.ts +40 -0
- package/dist/reply.mjs +1 -0
- package/dist/sandbox.d.mts +14 -13
- package/dist/sandbox.d.ts +14 -13
- package/dist/sandbox.mjs +1 -113
- package/dist/skill-markdown.d.mts +36 -0
- package/dist/skill-markdown.d.ts +36 -0
- package/dist/skill-markdown.mjs +1 -0
- package/dist/telemetry/index.d.mts +152 -33
- package/dist/telemetry/index.d.ts +152 -33
- package/dist/telemetry/index.mjs +1 -5
- package/package.json +18 -9
- package/dist/packem_shared/AGENT_MODULE-Dnt_-AAT.mjs +0 -24
- package/dist/packem_shared/VoiceSessionDO-BdwlLaXC.mjs +0 -297
- package/dist/packem_shared/adaptMcpResult-wtNMvLoP.mjs +0 -65
- package/dist/packem_shared/agentAsTool-CUHlWsmt.mjs +0 -98
- package/dist/packem_shared/base64-BVwtgRJV.mjs +0 -18
- package/dist/packem_shared/braintrustTelemetry-TP7Kwuuj.mjs +0 -47
- package/dist/packem_shared/buildModelMessages-BWFigaoo.mjs +0 -69
- package/dist/packem_shared/codeTool-CjgJOC9t.mjs +0 -122
- package/dist/packem_shared/collectAgenticMemoryTools-QrzpV-WX.mjs +0 -97
- package/dist/packem_shared/combineTelemetry-DCyaaWAI.mjs +0 -43
- package/dist/packem_shared/common-DQXayow6.mjs +0 -89
- package/dist/packem_shared/compileAgentWorkflow-DAfyUuI5.mjs +0 -78
- package/dist/packem_shared/consoleTelemetry--3sWfu1R.mjs +0 -93
- package/dist/packem_shared/createAgentContext-4xJGXNR4.mjs +0 -50
- package/dist/packem_shared/createAgentGenerate-DO7Z96zX.mjs +0 -192
- package/dist/packem_shared/createDispatchRunner-DSbp_dph-ZHTtxy3f.mjs +0 -69
- package/dist/packem_shared/defineAgent-DAwAZC9P.mjs +0 -148
- package/dist/packem_shared/defineSkill-Ctf_S-rz.mjs +0 -22
- package/dist/packem_shared/functionTool-D6lCa2jB.mjs +0 -20
- package/dist/packem_shared/graph-component-Bbaxxymp.mjs +0 -217
- package/dist/packem_shared/memory-D4FPcBsX.mjs +0 -12
- package/dist/packem_shared/normalizeEntityName-BouctxLC.mjs +0 -3
- package/dist/packem_shared/otlpTelemetry-CKgmWVLg.mjs +0 -170
- package/dist/packem_shared/runAgentLoop-M8PKbtWT.mjs +0 -493
- package/dist/packem_shared/runVoiceTurn-LnqLvCRR.mjs +0 -211
- package/dist/packem_shared/sandboxComponent-DR3pTwBL.mjs +0 -194
- package/dist/packem_shared/sentryTelemetry-A4F5ndh9.mjs +0 -36
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { defineWorkflow } from '@lunora/workflow';
|
|
2
|
-
import { runAgentLoop } from './runAgentLoop-M8PKbtWT.mjs';
|
|
3
|
-
import { createStreamGenerate, createAgentGenerate, createEpisodeExtract, createGraphExtract, createCompact } from './createAgentGenerate-DO7Z96zX.mjs';
|
|
4
|
-
import { agentDefaultName } from '../naming.mjs';
|
|
5
|
-
import { DEFAULT_AGENT_FUNCTION_PATHS } from './AGENT_MODULE-Dnt_-AAT.mjs';
|
|
6
|
-
import { c as createDispatchRunner } from './createDispatchRunner-DSbp_dph-ZHTtxy3f.mjs';
|
|
7
|
-
import { otlpTelemetry } from './otlpTelemetry-CKgmWVLg.mjs';
|
|
8
|
-
|
|
9
|
-
const resolveAgentRun = (contextRun, owner, env) => {
|
|
10
|
-
if (owner === void 0) {
|
|
11
|
-
return contextRun;
|
|
12
|
-
}
|
|
13
|
-
return createDispatchRunner({ env, identity: { userId: owner }, label: "@lunora/agent" });
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const withAutoOtlpTelemetry = (agent, env, conversationId) => {
|
|
17
|
-
const endpoint = env.LUNORA_OTLP_ENDPOINT;
|
|
18
|
-
if (typeof endpoint !== "string" || endpoint === "" || agent.telemetry?.isEnabled === false) {
|
|
19
|
-
return agent;
|
|
20
|
-
}
|
|
21
|
-
const token = typeof env.LUNORA_OTLP_TOKEN === "string" ? env.LUNORA_OTLP_TOKEN : void 0;
|
|
22
|
-
const existingList = [agent.telemetry?.integrations].flat().filter((integration) => integration !== void 0);
|
|
23
|
-
return {
|
|
24
|
-
...agent,
|
|
25
|
-
telemetry: {
|
|
26
|
-
...agent.telemetry,
|
|
27
|
-
// Tag every generation span with the run's thread as its conversation
|
|
28
|
-
// id (one thread = one multi-turn conversation), so the cloud groups a
|
|
29
|
-
// deployed agent's turns with no app wiring. Absent → ungrouped, as before.
|
|
30
|
-
integrations: [...existingList, otlpTelemetry({ conversationId, endpoint, token })],
|
|
31
|
-
isEnabled: true
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
const compileAgentWorkflow = (agent, exportName, options) => defineWorkflow({
|
|
36
|
-
handler: async (context) => {
|
|
37
|
-
const runtimeAgent = withAutoOtlpTelemetry(agent, context.env, context.params.threadKey);
|
|
38
|
-
return runAgentLoop({
|
|
39
|
-
agent: runtimeAgent,
|
|
40
|
-
// Automatic history compaction. Dormant unless the agent declares
|
|
41
|
-
// a `compaction` config; the loop gates on it, so any other agent
|
|
42
|
-
// takes the byte-identical no-compaction path.
|
|
43
|
-
compact: createCompact(),
|
|
44
|
-
env: context.env,
|
|
45
|
-
exportName,
|
|
46
|
-
// Run-end graph extraction. Dormant unless the agent declares a
|
|
47
|
-
// `kind: "graph"` memory source AND the run carries an owner — the
|
|
48
|
-
// loop gates on both, so a semantic-only agent takes the
|
|
49
|
-
// byte-identical no-extraction path.
|
|
50
|
-
extractGraph: createGraphExtract(),
|
|
51
|
-
// Run-end episode recording. Dormant unless the agent declares a
|
|
52
|
-
// `kind: "episodic"` memory source AND the run carries an owner —
|
|
53
|
-
// the loop gates on both, so any other agent is byte-identical.
|
|
54
|
-
extractEpisode: createEpisodeExtract(),
|
|
55
|
-
generate: createAgentGenerate(runtimeAgent, context.env),
|
|
56
|
-
instanceId: context.event.instanceId,
|
|
57
|
-
params: context.params,
|
|
58
|
-
paths: options?.paths ?? DEFAULT_AGENT_FUNCTION_PATHS,
|
|
59
|
-
// The loop reads its own owner-gated thread back through
|
|
60
|
-
// `agents:*` queries. The default `context.run` forwards no
|
|
61
|
-
// identity, so on an OWNED thread those reads would come back
|
|
62
|
-
// empty and the model would answer blind. `resolveAgentRun`
|
|
63
|
-
// dispatches an owner-scoped run under that verified identity so
|
|
64
|
-
// the owner gate admits the loop's reads (ownerless runs keep the
|
|
65
|
-
// identity-free `context.run`). See `resolve-run.ts`.
|
|
66
|
-
run: resolveAgentRun(context.run, context.params.owner, context.env),
|
|
67
|
-
step: context.step,
|
|
68
|
-
// The streaming seam is wired and ready, but stays dormant until a
|
|
69
|
-
// live token sink is threaded onto the run (a follow-up wires
|
|
70
|
-
// `onTokenDelta` to the stream transport). With no sink the loop
|
|
71
|
-
// takes the byte-identical non-streaming `generate` path.
|
|
72
|
-
streamGenerate: createStreamGenerate(runtimeAgent, context.env)
|
|
73
|
-
});
|
|
74
|
-
},
|
|
75
|
-
name: agent.name ?? agentDefaultName(exportName)
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
export { compileAgentWorkflow as default };
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { s as summarizeUsage, c as contentText, t as toolInputOf, d as describeError, r as readField, a as toolNameOf, b as describeToolOutcome } from './common-DQXayow6.mjs';
|
|
2
|
-
|
|
3
|
-
const defaultLogger = (level, message, fields) => {
|
|
4
|
-
const target = globalThis.console;
|
|
5
|
-
if (level === "error") {
|
|
6
|
-
target.error(message, fields);
|
|
7
|
-
} else if (level === "warn") {
|
|
8
|
-
target.warn(message, fields);
|
|
9
|
-
} else {
|
|
10
|
-
target.info(message, fields);
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
const consoleTelemetry = (options = {}) => {
|
|
14
|
-
const { functionId, logger = defaultLogger, recordInputs = false, recordOutputs = false } = options;
|
|
15
|
-
const prefix = functionId === void 0 ? "" : `[${functionId}] `;
|
|
16
|
-
const log = (level, message, fields) => {
|
|
17
|
-
logger(level, `${prefix}${message}`, fields);
|
|
18
|
-
};
|
|
19
|
-
return {
|
|
20
|
-
onAbort: (event) => {
|
|
21
|
-
log("warn", "agent operation aborted", {
|
|
22
|
-
callId: readField(event, "callId"),
|
|
23
|
-
reason: readField(event, "reason")
|
|
24
|
-
});
|
|
25
|
-
},
|
|
26
|
-
onEnd: (event) => {
|
|
27
|
-
log("info", "agent operation completed", {
|
|
28
|
-
callId: readField(event, "callId"),
|
|
29
|
-
finishReason: readField(event, "finishReason"),
|
|
30
|
-
operationId: readField(event, "operationId"),
|
|
31
|
-
usage: summarizeUsage(readField(event, "usage"))
|
|
32
|
-
});
|
|
33
|
-
},
|
|
34
|
-
onError: (error) => {
|
|
35
|
-
log("error", "agent operation errored", { error: describeError(error) });
|
|
36
|
-
},
|
|
37
|
-
onLanguageModelCallEnd: (event) => {
|
|
38
|
-
const fields = {
|
|
39
|
-
callId: readField(event, "callId"),
|
|
40
|
-
finishReason: readField(event, "finishReason"),
|
|
41
|
-
modelId: readField(event, "modelId"),
|
|
42
|
-
provider: readField(event, "provider"),
|
|
43
|
-
usage: summarizeUsage(readField(event, "usage"))
|
|
44
|
-
};
|
|
45
|
-
if (recordOutputs) {
|
|
46
|
-
fields["text"] = contentText(readField(event, "content"));
|
|
47
|
-
}
|
|
48
|
-
log("info", "language model call ended", fields);
|
|
49
|
-
},
|
|
50
|
-
onStart: (event) => {
|
|
51
|
-
log("info", "agent operation started", {
|
|
52
|
-
callId: readField(event, "callId"),
|
|
53
|
-
modelId: readField(event, "modelId"),
|
|
54
|
-
operationId: readField(event, "operationId"),
|
|
55
|
-
provider: readField(event, "provider")
|
|
56
|
-
});
|
|
57
|
-
},
|
|
58
|
-
onStepEnd: (event) => {
|
|
59
|
-
log("info", "agent step ended", {
|
|
60
|
-
finishReason: readField(event, "finishReason"),
|
|
61
|
-
stepNumber: readField(event, "stepNumber"),
|
|
62
|
-
usage: summarizeUsage(readField(event, "usage"))
|
|
63
|
-
});
|
|
64
|
-
},
|
|
65
|
-
onStepStart: (event) => {
|
|
66
|
-
log("info", "agent step started", { stepNumber: readField(event, "stepNumber") });
|
|
67
|
-
},
|
|
68
|
-
onToolExecutionEnd: (event) => {
|
|
69
|
-
const outcome = describeToolOutcome(event);
|
|
70
|
-
const fields = {
|
|
71
|
-
success: outcome.success,
|
|
72
|
-
tool: outcome.name,
|
|
73
|
-
toolExecutionMs: outcome.toolExecutionMs
|
|
74
|
-
};
|
|
75
|
-
if (!outcome.success) {
|
|
76
|
-
fields["error"] = describeError(outcome.error);
|
|
77
|
-
}
|
|
78
|
-
if (recordOutputs && outcome.success) {
|
|
79
|
-
fields["output"] = outcome.output;
|
|
80
|
-
}
|
|
81
|
-
log(outcome.success ? "info" : "warn", "tool execution ended", fields);
|
|
82
|
-
},
|
|
83
|
-
onToolExecutionStart: (event) => {
|
|
84
|
-
const fields = { tool: toolNameOf(event) };
|
|
85
|
-
if (recordInputs) {
|
|
86
|
-
fields["input"] = toolInputOf(event);
|
|
87
|
-
}
|
|
88
|
-
log("info", "tool execution started", fields);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
export { consoleTelemetry };
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { c as createDispatchRunner } from './createDispatchRunner-DSbp_dph-ZHTtxy3f.mjs';
|
|
2
|
-
import { LunoraError } from '@lunora/errors';
|
|
3
|
-
import { toFunctionReference, DEFAULT_AGENT_FUNCTION_PATHS } from './AGENT_MODULE-Dnt_-AAT.mjs';
|
|
4
|
-
|
|
5
|
-
const createAgentContext = (env, specs, dispatch) => {
|
|
6
|
-
const agents = {};
|
|
7
|
-
const patchThread = toFunctionReference(DEFAULT_AGENT_FUNCTION_PATHS.patchThread);
|
|
8
|
-
const resolveDispatch = () => dispatch ?? createDispatchRunner({ env, label: "@lunora/agent" });
|
|
9
|
-
for (const spec of specs) {
|
|
10
|
-
const resolve = () => {
|
|
11
|
-
const binding = env[spec.binding];
|
|
12
|
-
if (!binding || typeof binding.create !== "function" || typeof binding.get !== "function") {
|
|
13
|
-
throw new LunoraError(
|
|
14
|
-
"INTERNAL",
|
|
15
|
-
`@lunora/agent: no Workflow binding "${spec.binding}" on env for agent "${spec.exportName}" — run codegen/dev so wrangler.jsonc declares it`
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
return binding;
|
|
19
|
-
};
|
|
20
|
-
agents[spec.exportName] = {
|
|
21
|
-
cancel: async (id) => {
|
|
22
|
-
const instance = await resolve().get(id);
|
|
23
|
-
await instance.terminate();
|
|
24
|
-
try {
|
|
25
|
-
await resolveDispatch()(patchThread, { instanceId: id, status: "cancelled" });
|
|
26
|
-
} catch {
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
// Carried from the codegen spec (`defineAgent({ publicRun: true })`).
|
|
30
|
-
// Gates the public `agents:agentRun` mutation fail-closed; the
|
|
31
|
-
// server-side `run(...)` below is unaffected.
|
|
32
|
-
publicRun: spec.publicRun === true,
|
|
33
|
-
run: async (input, options) => {
|
|
34
|
-
const instance = await resolve().create({ ...options?.id === void 0 ? {} : { id: options.id }, params: input });
|
|
35
|
-
return { id: instance.id };
|
|
36
|
-
},
|
|
37
|
-
sendEvent: async (id, event) => {
|
|
38
|
-
const instance = await resolve().get(id);
|
|
39
|
-
await instance.sendEvent(event);
|
|
40
|
-
},
|
|
41
|
-
status: async (id) => {
|
|
42
|
-
const instance = await resolve().get(id);
|
|
43
|
-
return instance.status();
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
return agents;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export { createAgentContext as default };
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import { createAi } from '@lunora/ai';
|
|
2
|
-
import { LunoraError } from '@lunora/errors';
|
|
3
|
-
import { jsonSchema, generateText, streamText, Output, tool } from 'ai';
|
|
4
|
-
|
|
5
|
-
const toAgentUsage = (usage) => {
|
|
6
|
-
if (!usage) {
|
|
7
|
-
return void 0;
|
|
8
|
-
}
|
|
9
|
-
const result = {};
|
|
10
|
-
if (usage.inputTokens !== void 0) {
|
|
11
|
-
result.inputTokens = usage.inputTokens;
|
|
12
|
-
}
|
|
13
|
-
if (usage.outputTokens !== void 0) {
|
|
14
|
-
result.outputTokens = usage.outputTokens;
|
|
15
|
-
}
|
|
16
|
-
if (usage.totalTokens !== void 0) {
|
|
17
|
-
result.totalTokens = usage.totalTokens;
|
|
18
|
-
}
|
|
19
|
-
return Object.keys(result).length > 0 ? result : void 0;
|
|
20
|
-
};
|
|
21
|
-
const mapToolCalls = (calls) => calls.map((call) => {
|
|
22
|
-
return { id: call.toolCallId, input: call.input, name: call.toolName };
|
|
23
|
-
});
|
|
24
|
-
const resolveAgentModel = (model, env) => {
|
|
25
|
-
if (typeof model === "function") {
|
|
26
|
-
return model(env);
|
|
27
|
-
}
|
|
28
|
-
if (typeof model === "string") {
|
|
29
|
-
const binding = env["AI"];
|
|
30
|
-
if (!binding) {
|
|
31
|
-
throw new LunoraError(
|
|
32
|
-
"INTERNAL",
|
|
33
|
-
`@lunora/agent: the agent model "${model}" is a Workers AI id but there is no \`AI\` binding on the workflow env — declare the ai binding in wrangler.jsonc`
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
return createAi({ binding, env }).model(model);
|
|
37
|
-
}
|
|
38
|
-
return model;
|
|
39
|
-
};
|
|
40
|
-
const prepareAgentTurn = (agent, env) => {
|
|
41
|
-
const defaultModel = resolveAgentModel(agent.model, env);
|
|
42
|
-
const tools = {};
|
|
43
|
-
for (const [name, definition] of Object.entries(agent.tools ?? {})) {
|
|
44
|
-
tools[name] = tool({ description: definition.description, inputSchema: definition.inputSchema });
|
|
45
|
-
}
|
|
46
|
-
const output = agent.output === void 0 ? void 0 : Output.object({ schema: agent.output });
|
|
47
|
-
const staticSettings = {
|
|
48
|
-
...agent.temperature === void 0 ? {} : { temperature: agent.temperature },
|
|
49
|
-
...agent.maxOutputTokens === void 0 ? {} : { maxOutputTokens: agent.maxOutputTokens },
|
|
50
|
-
...agent.telemetry === void 0 ? {} : { telemetry: agent.telemetry },
|
|
51
|
-
...agent.repairToolCall === void 0 ? {} : { experimental_repairToolCall: agent.repairToolCall }
|
|
52
|
-
};
|
|
53
|
-
return { defaultModel, output, staticSettings, tools };
|
|
54
|
-
};
|
|
55
|
-
const buildTurnRequest = (base, { activeTools, messages, model, signal, toolChoice }) => {
|
|
56
|
-
const { defaultModel, output, staticSettings, tools } = base;
|
|
57
|
-
const exposed = activeTools === void 0 ? tools : Object.fromEntries(Object.entries(tools).filter(([name]) => activeTools.includes(name)));
|
|
58
|
-
return {
|
|
59
|
-
messages,
|
|
60
|
-
model: model ?? defaultModel,
|
|
61
|
-
...staticSettings,
|
|
62
|
-
...Object.keys(exposed).length > 0 ? { tools: exposed } : {},
|
|
63
|
-
...toolChoice === void 0 ? {} : { toolChoice },
|
|
64
|
-
...output === void 0 ? {} : { output },
|
|
65
|
-
// A voice barge-in aborts the turn mid-stream; the durable loop never
|
|
66
|
-
// sets it. Harmless on `generateText` (which accepts the same option).
|
|
67
|
-
...signal === void 0 ? {} : { abortSignal: signal }
|
|
68
|
-
};
|
|
69
|
-
};
|
|
70
|
-
const createAgentGenerate = (agent, env) => {
|
|
71
|
-
const base = prepareAgentTurn(agent, env);
|
|
72
|
-
return async (options) => {
|
|
73
|
-
const result = await generateText(buildTurnRequest(base, options));
|
|
74
|
-
const usage = toAgentUsage(result.usage);
|
|
75
|
-
return {
|
|
76
|
-
text: result.text,
|
|
77
|
-
toolCalls: mapToolCalls(result.toolCalls),
|
|
78
|
-
...usage === void 0 ? {} : { usage },
|
|
79
|
-
...base.output === void 0 ? {} : { output: result.output }
|
|
80
|
-
};
|
|
81
|
-
};
|
|
82
|
-
};
|
|
83
|
-
const createStreamGenerate = (agent, env) => {
|
|
84
|
-
const base = prepareAgentTurn(agent, env);
|
|
85
|
-
return async (options, onDelta) => {
|
|
86
|
-
const result = streamText(buildTurnRequest(base, options));
|
|
87
|
-
let streamed = "";
|
|
88
|
-
try {
|
|
89
|
-
for await (const delta of result.textStream) {
|
|
90
|
-
streamed += delta;
|
|
91
|
-
onDelta(delta);
|
|
92
|
-
}
|
|
93
|
-
} catch (error) {
|
|
94
|
-
if (options.signal?.aborted) {
|
|
95
|
-
return { text: streamed, toolCalls: [] };
|
|
96
|
-
}
|
|
97
|
-
throw error;
|
|
98
|
-
}
|
|
99
|
-
const [text, toolCalls, usage, output] = await Promise.all([
|
|
100
|
-
result.text,
|
|
101
|
-
result.toolCalls,
|
|
102
|
-
result.usage,
|
|
103
|
-
base.output === void 0 ? Promise.resolve(void 0) : result.output
|
|
104
|
-
]);
|
|
105
|
-
const agentUsage = toAgentUsage(usage);
|
|
106
|
-
return {
|
|
107
|
-
text,
|
|
108
|
-
toolCalls: mapToolCalls(toolCalls),
|
|
109
|
-
...agentUsage === void 0 ? {} : { usage: agentUsage },
|
|
110
|
-
...base.output === void 0 ? {} : { output }
|
|
111
|
-
};
|
|
112
|
-
};
|
|
113
|
-
};
|
|
114
|
-
const GRAPH_EXTRACTION_SCHEMA = jsonSchema({
|
|
115
|
-
additionalProperties: false,
|
|
116
|
-
properties: {
|
|
117
|
-
entities: {
|
|
118
|
-
description: "The distinct entities (people, orgs, places, things, concepts) named in the exchange.",
|
|
119
|
-
items: {
|
|
120
|
-
additionalProperties: false,
|
|
121
|
-
properties: {
|
|
122
|
-
name: { description: "The entity's canonical name.", type: "string" },
|
|
123
|
-
type: { description: "An optional coarse type, e.g. person, org, place, product.", type: "string" }
|
|
124
|
-
},
|
|
125
|
-
required: ["name"],
|
|
126
|
-
type: "object"
|
|
127
|
-
},
|
|
128
|
-
type: "array"
|
|
129
|
-
},
|
|
130
|
-
relations: {
|
|
131
|
-
description: "The directed relationships between the entities, as (src)-[label]->(dst) triples.",
|
|
132
|
-
items: {
|
|
133
|
-
additionalProperties: false,
|
|
134
|
-
properties: {
|
|
135
|
-
confidence: { description: "Confidence in the relation, 0..1.", type: "number" },
|
|
136
|
-
dst: { description: "The destination entity name (must appear in `entities`).", type: "string" },
|
|
137
|
-
label: { description: "The relationship, a short snake_case verb phrase, e.g. works_at.", type: "string" },
|
|
138
|
-
src: { description: "The source entity name (must appear in `entities`).", type: "string" }
|
|
139
|
-
},
|
|
140
|
-
required: ["src", "dst", "label"],
|
|
141
|
-
type: "object"
|
|
142
|
-
},
|
|
143
|
-
type: "array"
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
|
-
required: ["entities", "relations"],
|
|
147
|
-
type: "object"
|
|
148
|
-
});
|
|
149
|
-
const buildExtractionPrompt = (userInput, assistantText) => [
|
|
150
|
-
"Extract a knowledge graph of the durable facts stated in the following exchange.",
|
|
151
|
-
"Return the distinct entities and the directed relationships between them.",
|
|
152
|
-
"Only include facts actually stated — do not invent entities or relations. Prefer few, high-signal triples.",
|
|
153
|
-
"",
|
|
154
|
-
`User: ${userInput}`,
|
|
155
|
-
"",
|
|
156
|
-
`Assistant: ${assistantText}`
|
|
157
|
-
].join("\n");
|
|
158
|
-
const createGraphExtract = () => async ({ assistantText, env, model, userInput }) => {
|
|
159
|
-
const { output } = await generateText({
|
|
160
|
-
model: resolveAgentModel(model, env),
|
|
161
|
-
output: Output.object({ schema: GRAPH_EXTRACTION_SCHEMA }),
|
|
162
|
-
prompt: buildExtractionPrompt(userInput, assistantText)
|
|
163
|
-
});
|
|
164
|
-
return output;
|
|
165
|
-
};
|
|
166
|
-
const buildEpisodePrompt = (userInput, assistantText) => [
|
|
167
|
-
"Summarize the following exchange as ONE concise past-tense sentence for a long-term memory log.",
|
|
168
|
-
"Capture what the user wanted and what was done or decided — a durable fact worth recalling in a later conversation.",
|
|
169
|
-
"No preamble and no quotes: return only the sentence.",
|
|
170
|
-
"",
|
|
171
|
-
`User: ${userInput}`,
|
|
172
|
-
"",
|
|
173
|
-
`Assistant: ${assistantText}`
|
|
174
|
-
].join("\n");
|
|
175
|
-
const createEpisodeExtract = () => async ({ assistantText, env, model, userInput }) => {
|
|
176
|
-
const { text } = await generateText({
|
|
177
|
-
model: resolveAgentModel(model, env),
|
|
178
|
-
prompt: buildEpisodePrompt(userInput, assistantText)
|
|
179
|
-
});
|
|
180
|
-
return { summary: text.trim() };
|
|
181
|
-
};
|
|
182
|
-
const COMPACTION_SYSTEM = "You are compacting an ongoing conversation. Summarize the messages so far into a concise brief that preserves decisions made, facts established, open questions, and current task state — everything the assistant needs to continue coherently. Write it as notes for the assistant, not a reply to the user. No preamble.";
|
|
183
|
-
const createCompact = () => async ({ env, messages, model }) => {
|
|
184
|
-
const { text } = await generateText({
|
|
185
|
-
messages,
|
|
186
|
-
model: resolveAgentModel(model, env),
|
|
187
|
-
system: COMPACTION_SYSTEM
|
|
188
|
-
});
|
|
189
|
-
return text.trim();
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
export { createAgentGenerate, createCompact, createEpisodeExtract, createGraphExtract, createStreamGenerate, resolveAgentModel };
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { LunoraError } from '@lunora/errors';
|
|
2
|
-
|
|
3
|
-
const SCHEDULER_DISPATCH_PATH = "/_lunora/scheduler/dispatch";
|
|
4
|
-
const trimTrailingSlashes = (value) => {
|
|
5
|
-
let end = value.length;
|
|
6
|
-
while (end > 0 && value[end - 1] === "/") {
|
|
7
|
-
end -= 1;
|
|
8
|
-
}
|
|
9
|
-
return value.slice(0, end);
|
|
10
|
-
};
|
|
11
|
-
const toDispatchError = (label, status, rawBody) => {
|
|
12
|
-
try {
|
|
13
|
-
const parsed = JSON.parse(rawBody);
|
|
14
|
-
const errorBody = parsed?.error;
|
|
15
|
-
if (typeof errorBody === "object" && errorBody !== null && typeof errorBody.code === "string") {
|
|
16
|
-
const { code, data, message } = errorBody;
|
|
17
|
-
return new LunoraError(code, typeof message === "string" ? message : void 0, { data, status });
|
|
18
|
-
}
|
|
19
|
-
} catch {
|
|
20
|
-
}
|
|
21
|
-
return new LunoraError("INTERNAL", `${label}: function dispatch failed (${String(status)}): ${rawBody}`, { status });
|
|
22
|
-
};
|
|
23
|
-
const createDispatchRunner = (options) => {
|
|
24
|
-
const { label } = options;
|
|
25
|
-
const globalFetch = globalThis.fetch;
|
|
26
|
-
const fetchImpl = options.fetchImpl ?? (typeof globalFetch === "function" ? globalFetch.bind(globalThis) : void 0);
|
|
27
|
-
return async (function_, args, runOptions = {}) => {
|
|
28
|
-
if (typeof fetchImpl !== "function") {
|
|
29
|
-
throw new TypeError(`${label}: no fetch implementation available — pass fetchImpl or run on a platform with global fetch`);
|
|
30
|
-
}
|
|
31
|
-
const origin = options.env.LUNORA_ORIGIN_URL;
|
|
32
|
-
if (typeof origin !== "string" || origin.length === 0) {
|
|
33
|
-
throw new LunoraError("INTERNAL", `${label}: \`LUNORA_ORIGIN_URL\` must be set on the Worker env so a handler can call back into Lunora functions`);
|
|
34
|
-
}
|
|
35
|
-
const token = options.env.LUNORA_ADMIN_TOKEN;
|
|
36
|
-
if (typeof token !== "string" || token.length === 0) {
|
|
37
|
-
throw new LunoraError("INTERNAL", `${label}: \`LUNORA_ADMIN_TOKEN\` must be set on the Worker env to authenticate function dispatch`);
|
|
38
|
-
}
|
|
39
|
-
const url = `${trimTrailingSlashes(origin)}${SCHEDULER_DISPATCH_PATH}`;
|
|
40
|
-
const headers = { authorization: `Bearer ${token}`, "content-type": "application/json" };
|
|
41
|
-
if (options.identity?.userId !== void 0) {
|
|
42
|
-
headers["x-lunora-userid"] = options.identity.userId;
|
|
43
|
-
}
|
|
44
|
-
if (options.identity?.claims !== void 0) {
|
|
45
|
-
headers["x-lunora-identity"] = JSON.stringify(options.identity.claims);
|
|
46
|
-
}
|
|
47
|
-
const response = await fetchImpl(url, {
|
|
48
|
-
body: JSON.stringify({ args: args ?? {}, functionPath: function_.__lunoraRef, shardKey: runOptions.shardKey }),
|
|
49
|
-
headers,
|
|
50
|
-
method: "POST"
|
|
51
|
-
});
|
|
52
|
-
if (!response.ok) {
|
|
53
|
-
throw toDispatchError(label, response.status, await response.text());
|
|
54
|
-
}
|
|
55
|
-
const text = await response.text();
|
|
56
|
-
if (text.length === 0) {
|
|
57
|
-
return void 0;
|
|
58
|
-
}
|
|
59
|
-
try {
|
|
60
|
-
return JSON.parse(text);
|
|
61
|
-
} catch {
|
|
62
|
-
throw new LunoraError("INTERNAL", `${label}: function dispatch returned a non-JSON body (${String(response.status)}): ${text}`, {
|
|
63
|
-
status: response.status
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export { createDispatchRunner as c };
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { LunoraError } from '@lunora/errors';
|
|
2
|
-
import { collectAgenticMemoryTools } from './collectAgenticMemoryTools-QrzpV-WX.mjs';
|
|
3
|
-
import { agentAsTool } from './agentAsTool-CUHlWsmt.mjs';
|
|
4
|
-
import { i as isInjectedMemorySource } from './memory-D4FPcBsX.mjs';
|
|
5
|
-
import { SKILL_NAME_PATTERN, RESERVED_SKILL_NAME } from './defineSkill-Ctf_S-rz.mjs';
|
|
6
|
-
|
|
7
|
-
const TOOL_NAME_PATTERN = /^[a-zA-Z][\w-]*$/u;
|
|
8
|
-
const mergeSkillTools = (config, skills) => {
|
|
9
|
-
const tools = { ...config.tools };
|
|
10
|
-
for (const skill of skills) {
|
|
11
|
-
for (const [toolName, tool] of Object.entries(skill.tools ?? {})) {
|
|
12
|
-
if (Object.hasOwn(tools, toolName)) {
|
|
13
|
-
throw new LunoraError(
|
|
14
|
-
"INTERNAL",
|
|
15
|
-
`@lunora/agent: skill "${skill.name}" tool "${toolName}" collides with an existing tool — rename one (the agent's tool namespace is flat)`
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
tools[toolName] = tool;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return tools;
|
|
22
|
-
};
|
|
23
|
-
const composeInstructions = (config, skills) => {
|
|
24
|
-
const fragments = [];
|
|
25
|
-
for (const fragment of [config.instructions, ...skills.map((skill) => skill.instructions)]) {
|
|
26
|
-
if (fragment) {
|
|
27
|
-
fragments.push(fragment);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
if (fragments.length <= 1) {
|
|
31
|
-
return fragments[0];
|
|
32
|
-
}
|
|
33
|
-
return (context) => fragments.map((fragment) => typeof fragment === "function" ? fragment(context) : fragment).filter((text) => text.length > 0).join("\n\n");
|
|
34
|
-
};
|
|
35
|
-
const collectMemorySources = (config, skills) => {
|
|
36
|
-
const sources = [];
|
|
37
|
-
if (config.memory && isInjectedMemorySource(config.memory)) {
|
|
38
|
-
sources.push({ key: "default", ...config.memory });
|
|
39
|
-
}
|
|
40
|
-
for (const skill of skills) {
|
|
41
|
-
if (skill.knowledge && isInjectedMemorySource(skill.knowledge)) {
|
|
42
|
-
sources.push({ key: skill.name, ...skill.knowledge });
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return sources;
|
|
46
|
-
};
|
|
47
|
-
const assertValidSkillNames = (skills) => {
|
|
48
|
-
const seen = /* @__PURE__ */ new Set();
|
|
49
|
-
for (const skill of skills) {
|
|
50
|
-
if (typeof skill.name !== "string" || !SKILL_NAME_PATTERN.test(skill.name)) {
|
|
51
|
-
throw new LunoraError(
|
|
52
|
-
"INTERNAL",
|
|
53
|
-
`@lunora/agent: skill \`name\` must be a valid identifier (letters, digits, _ or -, starting with a letter), got ${JSON.stringify(skill.name)}`
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
if (skill.name === RESERVED_SKILL_NAME) {
|
|
57
|
-
throw new LunoraError(
|
|
58
|
-
"INTERNAL",
|
|
59
|
-
`@lunora/agent: skill name "${RESERVED_SKILL_NAME}" is reserved (it keys the agent's own \`memory\` source / the \`memory:retrieve\` step) — choose another name`
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
if (seen.has(skill.name)) {
|
|
63
|
-
throw new LunoraError(
|
|
64
|
-
"INTERNAL",
|
|
65
|
-
`@lunora/agent: skill name "${skill.name}" is used by more than one skill — rename one (a skill name keys its knowledge memory source, which must be unique)`
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
seen.add(skill.name);
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
const assertActiveToolsExposeMemory = (activeTools, agenticMemoryTools) => {
|
|
72
|
-
if (activeTools === void 0) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
const unreachable = Object.keys(agenticMemoryTools).filter((name) => !activeTools.includes(name));
|
|
76
|
-
if (unreachable.length > 0) {
|
|
77
|
-
throw new LunoraError(
|
|
78
|
-
"INTERNAL",
|
|
79
|
-
`@lunora/agent: \`activeTools\` omits the agentic-memory tool(s) ${unreachable.map((name) => `"${name}"`).join(", ")} — the model could never call them; add them to \`activeTools\` (or drop \`activeTools\` to expose every tool)`
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
const assertMemorySourcesConfigured = (config, skills) => {
|
|
84
|
-
const requireSource = (memory, label) => {
|
|
85
|
-
if (memory && memory.kind !== "graph" && memory.kind !== "episodic" && memory.source === void 0) {
|
|
86
|
-
throw new LunoraError("INTERNAL", `@lunora/agent: ${label} requires a \`source\` action unless \`kind: "graph"\` or \`kind: "episodic"\``);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
requireSource(config.memory, "`memory`");
|
|
90
|
-
for (const skill of skills) {
|
|
91
|
-
requireSource(skill.knowledge, `skill "${skill.name}" \`knowledge\``);
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
const defineAgent = (config) => {
|
|
95
|
-
const model = config.model;
|
|
96
|
-
if (model === void 0 || model === null || typeof model === "string" && model.length === 0) {
|
|
97
|
-
throw new LunoraError(
|
|
98
|
-
"INTERNAL",
|
|
99
|
-
"@lunora/agent: defineAgent requires a `model` (a Workers AI id, an AI SDK LanguageModel, or an (env) => model thunk)"
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
if (config.maxTurns !== void 0 && (!Number.isInteger(config.maxTurns) || config.maxTurns < 1)) {
|
|
103
|
-
throw new LunoraError("INTERNAL", "@lunora/agent: `maxTurns` must be a positive integer");
|
|
104
|
-
}
|
|
105
|
-
const skills = config.skills ?? [];
|
|
106
|
-
assertValidSkillNames(skills);
|
|
107
|
-
assertMemorySourcesConfigured(config, skills);
|
|
108
|
-
const tools = mergeSkillTools(config, skills);
|
|
109
|
-
const agenticMemoryTools = collectAgenticMemoryTools(config, skills);
|
|
110
|
-
for (const [toolName, tool] of Object.entries(agenticMemoryTools)) {
|
|
111
|
-
if (Object.hasOwn(tools, toolName)) {
|
|
112
|
-
throw new LunoraError(
|
|
113
|
-
"INTERNAL",
|
|
114
|
-
`@lunora/agent: agentic-memory tool "${toolName}" collides with an existing tool — rename one (the agent's tool namespace is flat)`
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
tools[toolName] = tool;
|
|
118
|
-
}
|
|
119
|
-
const hasAgenticTools = Object.keys(agenticMemoryTools).length > 0;
|
|
120
|
-
assertActiveToolsExposeMemory(config.activeTools, agenticMemoryTools);
|
|
121
|
-
for (const name of Object.keys(tools)) {
|
|
122
|
-
if (!TOOL_NAME_PATTERN.test(name)) {
|
|
123
|
-
throw new LunoraError("INTERNAL", `@lunora/agent: tool name "${name}" is not a valid identifier (letters, digits, _ or -, starting with a letter)`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
const memorySources = collectMemorySources(config, skills);
|
|
127
|
-
const composedInstructions = composeInstructions(config, skills);
|
|
128
|
-
return {
|
|
129
|
-
...config,
|
|
130
|
-
asTool: agentAsTool,
|
|
131
|
-
isLunoraAgent: true,
|
|
132
|
-
...skills.some((skill) => Boolean(skill.instructions)) ? { instructions: composedInstructions } : {},
|
|
133
|
-
...memorySources.length > 0 ? { memorySources } : {},
|
|
134
|
-
...skills.length > 0 || hasAgenticTools ? { tools } : {}
|
|
135
|
-
};
|
|
136
|
-
};
|
|
137
|
-
const isAgentDefinition = (value) => typeof value === "object" && value !== null && value.isLunoraAgent === true;
|
|
138
|
-
const defineAgentTool = (config) => {
|
|
139
|
-
if (typeof config.execute !== "function") {
|
|
140
|
-
throw new LunoraError("INTERNAL", "@lunora/agent: defineAgentTool requires an `execute` function");
|
|
141
|
-
}
|
|
142
|
-
if (typeof config.description !== "string" || config.description.length === 0) {
|
|
143
|
-
throw new LunoraError("INTERNAL", "@lunora/agent: defineAgentTool requires a non-empty `description` (the model decides from it)");
|
|
144
|
-
}
|
|
145
|
-
return { ...config, isLunoraAgentTool: true };
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
export { defineAgent, defineAgentTool, isAgentDefinition };
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { LunoraError } from '@lunora/errors';
|
|
2
|
-
|
|
3
|
-
const SKILL_NAME_PATTERN = /^[a-zA-Z][\w-]*$/u;
|
|
4
|
-
const RESERVED_SKILL_NAME = "default";
|
|
5
|
-
const defineSkill = (config) => {
|
|
6
|
-
if (typeof config.name !== "string" || !SKILL_NAME_PATTERN.test(config.name)) {
|
|
7
|
-
throw new LunoraError(
|
|
8
|
-
"INTERNAL",
|
|
9
|
-
`@lunora/agent: defineSkill requires a \`name\` that is a valid identifier (letters, digits, _ or -, starting with a letter), got ${JSON.stringify(config.name)}`
|
|
10
|
-
);
|
|
11
|
-
}
|
|
12
|
-
if (config.name === RESERVED_SKILL_NAME) {
|
|
13
|
-
throw new LunoraError(
|
|
14
|
-
"INTERNAL",
|
|
15
|
-
`@lunora/agent: skill name "${RESERVED_SKILL_NAME}" is reserved (it keys the agent's own \`memory\` source / the historic \`memory:retrieve\` step) — choose another name`
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
return { ...config, isLunoraSkill: true };
|
|
19
|
-
};
|
|
20
|
-
const isSkillDefinition = (value) => typeof value === "object" && value !== null && value.isLunoraSkill === true;
|
|
21
|
-
|
|
22
|
-
export { RESERVED_SKILL_NAME, SKILL_NAME_PATTERN, defineSkill, isSkillDefinition };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { LunoraError } from '@lunora/errors';
|
|
2
|
-
import { toFunctionReference } from './AGENT_MODULE-Dnt_-AAT.mjs';
|
|
3
|
-
|
|
4
|
-
const functionTool = (reference, options) => {
|
|
5
|
-
if (typeof options.description !== "string" || options.description.length === 0) {
|
|
6
|
-
throw new LunoraError("INTERNAL", "@lunora/agent: functionTool requires a non-empty `description` (the model decides from it)");
|
|
7
|
-
}
|
|
8
|
-
if (options.inputSchema === void 0) {
|
|
9
|
-
throw new LunoraError("INTERNAL", "@lunora/agent: functionTool requires an `inputSchema` (a zod schema or `jsonSchema(...)`)");
|
|
10
|
-
}
|
|
11
|
-
const target = toFunctionReference(reference);
|
|
12
|
-
return {
|
|
13
|
-
description: options.description,
|
|
14
|
-
execute: (input, context) => context.run(target, input),
|
|
15
|
-
inputSchema: options.inputSchema,
|
|
16
|
-
isLunoraAgentTool: true
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export { functionTool };
|