@almadar/integrations 2.41.0 → 2.42.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/dist/{BaseIntegration-CWdas-N_.d.ts → BaseIntegration-D_iNTesu.d.ts} +3 -1
- package/dist/index.d.ts +35 -17
- package/dist/index.js +132 -2
- package/dist/index.js.map +1 -1
- package/dist/integrations/github/index.d.ts +1 -1
- package/dist/mocks/index.d.ts +1 -1
- package/dist/mocks/index.js.map +1 -1
- package/dist/runtime/index.d.ts +3 -2
- package/dist/runtime/index.js +131 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/{store-DG5OGiuQ.d.ts → store-DcennSSh.d.ts} +7 -101
- package/package.json +4 -4
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { g as IntegrationParams, I as IntegrationCallContext, d as IntegrationFactory } from '../BaseIntegration-
|
|
2
|
-
import { o as IntegrationName, m as IntegrationActionName, n as IntegrationContracts, e as CredentialStore } from '../store-
|
|
1
|
+
import { g as IntegrationParams, I as IntegrationCallContext, d as IntegrationFactory } from '../BaseIntegration-D_iNTesu.js';
|
|
2
|
+
import { o as IntegrationName, m as IntegrationActionName, n as IntegrationContracts, e as CredentialStore } from '../store-DcennSSh.js';
|
|
3
3
|
import '@almadar/core';
|
|
4
|
+
import '@almadar/llm';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Signature of the call-service handler returned by `createCallServiceHandler`
|
package/dist/runtime/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import webpush from 'web-push';
|
|
|
13
13
|
import { Readable } from 'stream';
|
|
14
14
|
import { getAvailableProvider, LLMClient, EmbeddingClient } from '@almadar/llm';
|
|
15
15
|
import { z } from 'zod';
|
|
16
|
+
import { findInputByAddress, payloadSchemaToJsonSchema, EventPayloadSchema } from '@almadar/core';
|
|
16
17
|
import { execSync, spawn } from 'child_process';
|
|
17
18
|
import { tmpdir } from 'os';
|
|
18
19
|
import * as oidc from 'openid-client';
|
|
@@ -1973,6 +1974,123 @@ var EsignIntegration = class extends BaseIntegration {
|
|
|
1973
1974
|
}
|
|
1974
1975
|
};
|
|
1975
1976
|
registerIntegration("esign", EsignIntegration);
|
|
1977
|
+
var DEFAULT_MAX_STEPS = 8;
|
|
1978
|
+
var TOOL_NAME = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
1979
|
+
function toolName(raw) {
|
|
1980
|
+
if (!TOOL_NAME.test(raw)) {
|
|
1981
|
+
throw new Error(`call-tools: tool name '${raw}' is not a valid tool name (letters, digits, _ and -, at most 64)`);
|
|
1982
|
+
}
|
|
1983
|
+
return raw;
|
|
1984
|
+
}
|
|
1985
|
+
function buildTools(host, tools) {
|
|
1986
|
+
const inputs = host.inputs();
|
|
1987
|
+
const out = /* @__PURE__ */ new Map();
|
|
1988
|
+
for (const tool of tools) {
|
|
1989
|
+
if (tool.event !== void 0) {
|
|
1990
|
+
const input = findInputByAddress(inputs, tool.event, host.caller);
|
|
1991
|
+
if (!input) throw new Error(`call-tools: '${tool.event}' is not a declared external input`);
|
|
1992
|
+
const name = toolName(tool.event.split(".").join("__"));
|
|
1993
|
+
out.set(name, {
|
|
1994
|
+
def: {
|
|
1995
|
+
type: "function",
|
|
1996
|
+
function: { name, description: input.description ?? tool.event, parameters: payloadSchemaToJsonSchema(input.payloadSchema) }
|
|
1997
|
+
},
|
|
1998
|
+
target: { kind: "input", address: tool.event, input }
|
|
1999
|
+
});
|
|
2000
|
+
} else if (tool.read !== void 0) {
|
|
2001
|
+
const name = toolName(`read__${tool.read}`);
|
|
2002
|
+
out.set(name, {
|
|
2003
|
+
def: {
|
|
2004
|
+
type: "function",
|
|
2005
|
+
function: { name, description: `Read the ${tool.read} rows you may see`, parameters: { type: "object", properties: {} } }
|
|
2006
|
+
},
|
|
2007
|
+
target: { kind: "read", entity: tool.read }
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
return out;
|
|
2012
|
+
}
|
|
2013
|
+
function dispatchFailure(response) {
|
|
2014
|
+
if (response.rejections && response.rejections.length > 0) return response.rejections.map((r) => r.code).join(", ");
|
|
2015
|
+
if (response.guardFailed !== void 0) return `guard failed: ${response.guardFailed}`;
|
|
2016
|
+
if (!response.success) return response.error ?? "dispatch failed";
|
|
2017
|
+
const failed = (response.effectResults ?? []).find((r) => !r.success);
|
|
2018
|
+
if (failed) return failed.error ?? `${failed.effect} failed`;
|
|
2019
|
+
if (!response.transitioned) return "no transition";
|
|
2020
|
+
return void 0;
|
|
2021
|
+
}
|
|
2022
|
+
function parseArgs(args) {
|
|
2023
|
+
let value;
|
|
2024
|
+
try {
|
|
2025
|
+
value = JSON.parse(args === "" ? "{}" : args);
|
|
2026
|
+
} catch {
|
|
2027
|
+
value = void 0;
|
|
2028
|
+
}
|
|
2029
|
+
return EventPayloadSchema.safeParse(value);
|
|
2030
|
+
}
|
|
2031
|
+
async function runToolLoop(client, host, request) {
|
|
2032
|
+
const tools = buildTools(host, request.tools);
|
|
2033
|
+
const defs = [...tools.values()].map((t) => t.def);
|
|
2034
|
+
const maxSteps = request.maxSteps ?? DEFAULT_MAX_STEPS;
|
|
2035
|
+
const conversation = [
|
|
2036
|
+
...request.instructions !== void 0 ? [{ role: "system", content: request.instructions }] : [],
|
|
2037
|
+
...request.messages.map((m) => ({ role: m.role, content: m.content }))
|
|
2038
|
+
];
|
|
2039
|
+
const steps = [];
|
|
2040
|
+
const usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0, modelCalls: 0 };
|
|
2041
|
+
while (usage.modelCalls < maxSteps) {
|
|
2042
|
+
const turn = await client.callWithTools({ messages: conversation, tools: defs });
|
|
2043
|
+
usage.modelCalls += 1;
|
|
2044
|
+
if (turn.usage) {
|
|
2045
|
+
usage.promptTokens += turn.usage.promptTokens;
|
|
2046
|
+
usage.completionTokens += turn.usage.completionTokens;
|
|
2047
|
+
usage.totalTokens += turn.usage.totalTokens;
|
|
2048
|
+
}
|
|
2049
|
+
conversation.push(turn.message);
|
|
2050
|
+
const calls = turn.message.tool_calls ?? [];
|
|
2051
|
+
if (calls.length === 0) return { reply: turn.message.content ?? "", steps, usage };
|
|
2052
|
+
for (const call of calls) {
|
|
2053
|
+
const args = call.function.arguments;
|
|
2054
|
+
const tool = tools.get(call.function.name);
|
|
2055
|
+
let content;
|
|
2056
|
+
if (!tool) {
|
|
2057
|
+
steps.push({ kind: "invalid", target: call.function.name, args, ok: false, detail: "not an allowed tool" });
|
|
2058
|
+
content = JSON.stringify({ error: `'${call.function.name}' is not one of your tools` });
|
|
2059
|
+
} else if (tool.target.kind === "read") {
|
|
2060
|
+
const rows = await host.read(tool.target.entity);
|
|
2061
|
+
steps.push({ kind: "read", target: tool.target.entity, args, ok: true });
|
|
2062
|
+
content = JSON.stringify({ rows });
|
|
2063
|
+
} else {
|
|
2064
|
+
const parsed = parseArgs(args);
|
|
2065
|
+
if (!parsed.success) {
|
|
2066
|
+
steps.push({ kind: "input", target: tool.target.address, args, ok: false, detail: "arguments are not a JSON object" });
|
|
2067
|
+
content = JSON.stringify({ error: "arguments must be a JSON object" });
|
|
2068
|
+
} else {
|
|
2069
|
+
const { input } = tool.target;
|
|
2070
|
+
const response = await host.dispatchInput(input.orbital, {
|
|
2071
|
+
targetTrait: input.trait,
|
|
2072
|
+
event: input.event,
|
|
2073
|
+
payload: parsed.data
|
|
2074
|
+
});
|
|
2075
|
+
const detail = dispatchFailure(response);
|
|
2076
|
+
steps.push({ kind: "input", target: tool.target.address, args, ok: detail === void 0, ...detail !== void 0 ? { detail } : {} });
|
|
2077
|
+
content = JSON.stringify(response);
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
conversation.push({ role: "tool", content, tool_call_id: call.id });
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
throw new Error(`call-tools: no reply after ${maxSteps} model calls`);
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
// src/integrations/llm/index.ts
|
|
2087
|
+
var CallToolsParamsSchema = z.object({
|
|
2088
|
+
messages: z.array(z.object({ role: z.enum(["user", "assistant"]), content: z.string() })),
|
|
2089
|
+
tools: z.array(z.object({ event: z.string().optional(), read: z.string().optional() })),
|
|
2090
|
+
instructions: z.string().optional(),
|
|
2091
|
+
maxSteps: z.number().int().positive().optional(),
|
|
2092
|
+
model: z.string().optional()
|
|
2093
|
+
});
|
|
1976
2094
|
var LLMIntegration = class extends BaseIntegration {
|
|
1977
2095
|
constructor(config) {
|
|
1978
2096
|
super(config);
|
|
@@ -2013,7 +2131,7 @@ var LLMIntegration = class extends BaseIntegration {
|
|
|
2013
2131
|
}
|
|
2014
2132
|
return this.embeddings;
|
|
2015
2133
|
}
|
|
2016
|
-
async execute(action, params) {
|
|
2134
|
+
async execute(action, params, context) {
|
|
2017
2135
|
const validation = this.validateParams(action, params);
|
|
2018
2136
|
if (!validation.valid) return this.validationFailure(action, validation.errors);
|
|
2019
2137
|
const startTime = Date.now();
|
|
@@ -2035,6 +2153,10 @@ var LLMIntegration = class extends BaseIntegration {
|
|
|
2035
2153
|
case "embed":
|
|
2036
2154
|
data = await this.executeWithRetry(() => this.embed(params));
|
|
2037
2155
|
break;
|
|
2156
|
+
// Never retried: a retry would re-fire inputs the first attempt already fired.
|
|
2157
|
+
case "call-tools":
|
|
2158
|
+
data = await this.callTools(params, context);
|
|
2159
|
+
break;
|
|
2038
2160
|
default:
|
|
2039
2161
|
throw new UnknownActionError(this.config.name, action);
|
|
2040
2162
|
}
|
|
@@ -2125,6 +2247,14 @@ Return ONLY valid JSON matching the schema.`,
|
|
|
2125
2247
|
});
|
|
2126
2248
|
return result;
|
|
2127
2249
|
}
|
|
2250
|
+
async callTools(params, context) {
|
|
2251
|
+
if (!context?.host) {
|
|
2252
|
+
throw new Error("llm.call-tools needs host ports: run it from a host that lends the running app (call-service on a server)");
|
|
2253
|
+
}
|
|
2254
|
+
const request = CallToolsParamsSchema.parse(params);
|
|
2255
|
+
const client = request.model !== void 0 ? new LLMClient({ provider: this.provider, model: request.model }) : this.getClient();
|
|
2256
|
+
return runToolLoop(client, context.host, request);
|
|
2257
|
+
}
|
|
2128
2258
|
async embed(params) {
|
|
2129
2259
|
const { texts } = params;
|
|
2130
2260
|
if (!Array.isArray(texts)) {
|