npm package distribtion

This commit is contained in:
2025-09-03 19:52:41 +00:00
parent 54ef2e003a
commit 918fa2e833
6 changed files with 371 additions and 9 deletions

1
.gitignore vendored
View File

@@ -1,2 +1 @@
node_modules
dist

View File

@@ -1,8 +1,3 @@
<p align="center">
<img src="./assets/logo.svg" width="600">
</p>
<br>
# JLINC Langchain Tracer
The JLINC Langchain Tracer is the official way to implement the zero-knowledge third-party auditing provided by the [JLINC Server](https://gitea.jlinc.io/jlinc-labs/jlinc-server) inside any Langchain-based infrastructure.

127
dist/tracer.d.ts vendored Normal file
View File

@@ -0,0 +1,127 @@
export type JLINCTracerFields = {
dataStoreApiUrl?: string | undefined;
dataStoreApiKey?: string | undefined;
archiveApiUrl?: string | undefined;
archiveApiKey?: string | undefined;
systemPrefix?: string | undefined;
agreementId?: string | null | undefined;
debug?: boolean | undefined;
};
export type SerializedRun = {
name?: string | undefined;
start_time?: number | undefined;
end_time?: number | undefined;
trace_id?: string | undefined;
inputs?: any;
outputs?: any;
extra?: {
metadata?: {
ls_provider?: string;
ls_model_name?: string;
};
} | undefined;
};
/**
* @typedef {Object} JLINCTracerFields
* @property {string} [dataStoreApiUrl]
* @property {string} [dataStoreApiKey]
* @property {string} [archiveApiUrl]
* @property {string} [archiveApiKey]
* @property {string} [systemPrefix]
* @property {string|null} [agreementId]
* @property {boolean} [debug]
*/
/**
* @typedef {Object} SerializedRun
* @property {string} [name]
* @property {number} [start_time]
* @property {number} [end_time]
* @property {string} [trace_id]
* @property {any} [inputs]
* @property {any} [outputs]
* @property {{ metadata?: { ls_provider?: string, ls_model_name?: string } }} [extra]
*/
/**
* @extends {LangChainTracer}
*/
export class JLINCTracer extends LangChainTracer {
/**
* @param {JLINCTracerFields} [fields={}]
*/
constructor(fields?: JLINCTracerFields);
/** @type {string} */
dataStoreApiUrl: string;
/** @type {string} */
dataStoreApiKey: string;
/** @type {string} */
archiveApiUrl: string;
/** @type {string} */
archiveApiKey: string;
/** @type {string} */
systemPrefix: string;
/** @type {string|null} */
agreementId: string | null;
/** @type {boolean} */
debug: boolean;
/** @type {string|null} */
domain: string | null;
/** @type {Set<string>} */
entities: Set<string>;
/**
* @param {any} run
* @returns {Promise<void>}
*/
onRunCreate(run: any): Promise<void>;
/**
* @param {any} run
* @returns {Promise<void>}
*/
onRunUpdate(run: any): Promise<void>;
/**
* @returns {Promise<void>}
*/
getDefaultProjectName(): Promise<void>;
/**
* @param {SerializedRun} serialized
* @returns {Promise<void>}
*/
onLLMStart(serialized: SerializedRun): Promise<void>;
/**
* @param {SerializedRun} serialized
* @returns {Promise<void>}
*/
onLLMEnd(serialized: SerializedRun): Promise<void>;
/**
* @param {SerializedRun} serialized
* @returns {Promise<void>}
*/
onToolStart(serialized: SerializedRun): Promise<void>;
/**
* @param {SerializedRun} serialized
* @returns {Promise<void>}
*/
onToolEnd(serialized: SerializedRun): Promise<void>;
/**
* @param {string} dir
* @param {any} payload
* @returns {Promise<any>}
*/
_postToApi(dir: string, payload: any): Promise<any>;
/**
* @param {string} entityShortName
* @returns {Promise<void>}
*/
_setEntity(entityShortName: string): Promise<void>;
/**
* @param {string} input
* @returns {string}
*/
_sanitize(input: string): string;
/**
* @param {any} payload
* @param {'in' | 'out'} direction
* @returns {Promise<void>}
*/
_jlincTrace(payload: any, direction: "in" | "out"): Promise<void>;
}
import { LangChainTracer } from "@langchain/core/dist/tracers/tracer_langchain";

241
dist/tracer.js vendored Normal file
View File

@@ -0,0 +1,241 @@
const { LangChainTracer } = require("@langchain/core/tracers/tracer_langchain");
const axios = require("axios");
/**
* @typedef {Object} JLINCTracerFields
* @property {string} [dataStoreApiUrl]
* @property {string} [dataStoreApiKey]
* @property {string} [archiveApiUrl]
* @property {string} [archiveApiKey]
* @property {string} [systemPrefix]
* @property {string|null} [agreementId]
* @property {boolean} [debug]
*/
/**
* @typedef {Object} SerializedRun
* @property {string} [name]
* @property {number} [start_time]
* @property {number} [end_time]
* @property {string} [trace_id]
* @property {any} [inputs]
* @property {any} [outputs]
* @property {{ metadata?: { ls_provider?: string, ls_model_name?: string } }} [extra]
*/
/**
* @extends {LangChainTracer}
*/
class JLINCTracer extends LangChainTracer {
/**
* @param {JLINCTracerFields} [fields={}]
*/
constructor(fields = {}) {
super(fields);
const defaultDataStoreApiUrl = "https://api-test.jlinc.io";
const defaultDataStoreApiKey = "";
const defaultArchiveApiUrl = "https://archive-test.jlinc.io";
const defaultArchiveApiKey = "";
const defaultSystemPrefix = "MyProject";
/** @type {string} */
this.dataStoreApiUrl = fields.dataStoreApiUrl ?? defaultDataStoreApiUrl;
/** @type {string} */
this.dataStoreApiKey = fields.dataStoreApiKey ?? defaultDataStoreApiKey;
/** @type {string} */
this.archiveApiUrl = fields.archiveApiUrl ?? defaultArchiveApiUrl;
/** @type {string} */
this.archiveApiKey = fields.archiveApiKey ?? defaultArchiveApiKey;
/** @type {string} */
this.systemPrefix = this._sanitize(fields.systemPrefix ?? defaultSystemPrefix);
/** @type {string|null} */
this.agreementId = fields.agreementId ?? null;
/** @type {boolean} */
this.debug = fields.debug ?? false;
/** @type {string|null} */
this.domain = null;
/** @type {Set<string>} */
this.entities = new Set();
}
/**
* @param {any} run
* @returns {Promise<void>}
*/
async onRunCreate(run) { }
/**
* @param {any} run
* @returns {Promise<void>}
*/
async onRunUpdate(run) { }
/**
* @returns {Promise<void>}
*/
async getDefaultProjectName() {
return this.systemPrefix;
}
/**
* @param {SerializedRun} serialized
* @returns {Promise<void>}
*/
async onLLMStart(serialized) {
if (this.debug) {
console.log(`\nJLINC: onLLMStart`);
console.log(`---------------------------------------------`);
}
await this._jlincTrace({
event: "llm_start",
name: serialized?.name || "unknown",
ts: serialized?.start_time,
provider: serialized?.extra?.metadata,
traceId: serialized?.trace_id,
inputs: serialized?.inputs,
}, 'out');
}
/**
* @param {SerializedRun} serialized
* @returns {Promise<void>}
*/
async onLLMEnd(serialized) {
if (this.debug) {
console.log(`\nJLINC: onLLMEnd`);
console.log(`---------------------------------------------`);
}
await this._jlincTrace({
event: "llm_end",
name: serialized?.name || "unknown",
ts: serialized?.end_time,
provider: serialized?.extra?.metadata,
traceId: serialized?.trace_id,
outputs: serialized?.outputs,
}, 'in');
}
/**
* @param {SerializedRun} serialized
* @returns {Promise<void>}
*/
async onToolStart(serialized) {
if (this.debug) {
console.log(`\nJLINC: onToolStart`);
console.log(`---------------------------------------------`);
}
await this._jlincTrace({
event: "tool_start",
name: serialized?.name || "unknown",
ts: serialized?.start_time,
provider: serialized?.extra?.metadata,
traceId: serialized?.trace_id,
inputs: serialized?.inputs,
}, 'out');
}
/**
* @param {SerializedRun} serialized
* @returns {Promise<void>}
*/
async onToolEnd(serialized) {
if (this.debug) {
console.log(`\nJLINC: onToolEnd`);
console.log(`---------------------------------------------`);
}
await this._jlincTrace({
event: "tool_end",
name: serialized?.name || "unknown",
ts: serialized?.end_time,
provider: serialized?.extra?.metadata,
traceId: serialized?.trace_id,
outputs: serialized?.outputs,
}, 'in');
}
/**
* @param {string} dir
* @param {any} payload
* @returns {Promise<any>}
*/
async _postToApi(dir, payload) {
const response = await axios.post(
`${this.dataStoreApiUrl}/api/v1/data/${dir}`,
payload,
{
headers: {
'Authorization': `Bearer ${this.dataStoreApiKey}`,
}
}
);
return response.data;
}
/**
* @param {string} entityShortName
* @returns {Promise<void>}
*/
async _setEntity(entityShortName) {
if (!this.entities.has(entityShortName)) {
let recipient = null;
try {
recipient = await this._postToApi(`entity/get`, { shortName: entityShortName });
} catch (e) {
recipient = await this._postToApi(`entity/create`, { shortName: entityShortName });
}
this.entities.add(entityShortName);
}
}
/**
* @param {string} input
* @returns {string}
*/
_sanitize(input) {
return input.replace(/[^a-zA-Z0-9._-]/g, '_');
}
/**
* @param {any} payload
* @param {'in' | 'out'} direction
* @returns {Promise<void>}
*/
async _jlincTrace(payload, direction) {
try {
if (!this.domain) {
const domains = await this._postToApi(`entity/domains/get`, {});
this.domain = domains[0];
}
let entityShortName = `${this.systemPrefix}-${this._sanitize(payload.name)}`;
payload?.provider?.ls_provider && (entityShortName += `-${this._sanitize(payload.provider.ls_provider)}`);
payload?.provider?.ls_model_name && (entityShortName += `-${this._sanitize(payload.provider.ls_model_name)}`);
entityShortName += `@${this.domain}`;
await this._setEntity(entityShortName);
const systemShortName = `${this.systemPrefix}-system@${this.domain}`;
await this._setEntity(systemShortName);
const recipientShortName = direction === 'in' ? systemShortName : entityShortName;
const senderShortName = direction === 'out' ? systemShortName : entityShortName;
const data = {
type: 'data',
senderShortName,
recipientShortName,
agreementId: this.agreementId,
data: payload,
archive: {
url: this.archiveApiUrl,
key: this.archiveApiKey,
}
};
const event = await this._postToApi(`event/produce`, data);
if (this.debug) {
console.log(JSON.stringify({ event }, null, 2));
}
} catch (error) {
console.error("[Tracer] Failed to log event:", error.message);
}
}
}
module.exports = { JLINCTracer }

2
package-lock.json generated
View File

@@ -1,5 +1,5 @@
{
"name": "jlinc-tracer",
"name": "@jlinc/langchain",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,

View File

@@ -1,7 +1,7 @@
{
"name": "jlinc-tracer",
"name": "@jlinc/langchain",
"version": "0.1.0",
"description": "A LangChain callback plugin that logs events to the JLINC API.",
"description": "A LangChain plugin that logs events to the JLINC API.",
"main": "dist/tracer.js",
"types": "dist/tracer.d.ts",
"scripts": {