Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .fernignore
Original file line number Diff line number Diff line change
@@ -1 +1,21 @@
# Specify files that shouldn't be modified by Fern

# Custom code

src/otel
src/eval_utils
src/decorators
src/index.ts
src/humanloop.client.ts

# Tests

tests

# CI Action

.github/workflows/ci.yml

# Prettier

.prettierrc.yml
108 changes: 56 additions & 52 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,59 @@ name: ci
on: [push]

jobs:
compile:
runs-on: ubuntu-latest

steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3

- name: Compile
run: yarn && yarn build

test:
runs-on: ubuntu-latest

steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3

- name: Compile
run: yarn && yarn test

publish:
needs: [ compile, test ]
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Set up node
uses: actions/setup-node@v3
- name: Install dependencies
run: yarn install
- name: Build
run: yarn build

- name: Publish to npm
run: |
npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
if [[ ${GITHUB_REF} == *alpha* ]]; then
npm publish --access public --tag alpha
elif [[ ${GITHUB_REF} == *beta* ]]; then
npm publish --access public --tag beta
else
npm publish --access public
fi
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
compile:
runs-on: ubuntu-latest

steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3

- name: Compile
run: yarn && yarn build

test:
runs-on: ubuntu-latest

steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3

- name: Compile
run: yarn && yarn test
env:
OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
ANTHROPIC_KEY: ${{ secrets.ANTHROPIC_KEY }}
COHERE_KEY: ${{ secrets.COHERE_KEY }}

publish:
needs: [compile, test]
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Set up node
uses: actions/setup-node@v3
- name: Install dependencies
run: yarn install
- name: Build
run: yarn build

- name: Publish to npm
run: |
npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
if [[ ${GITHUB_REF} == *alpha* ]]; then
npm publish --access public --tag alpha
elif [[ ${GITHUB_REF} == *beta* ]]; then
npm publish --access public --tag beta
else
npm publish --access public
fi
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
.DS_Store
/dist
/dist
.env
3 changes: 3 additions & 0 deletions .prettierrc.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
tabWidth: 4
printWidth: 120
semi: true
plugins:
- "prettier-plugin-organize-imports"
41 changes: 30 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,51 @@
"format": "prettier . --write --ignore-unknown",
"build": "tsc",
"prepack": "cp -rv dist/. .",
"test": "jest"
"test": "jest --detectOpenHandles --forceExit"
},
"dependencies": {
"url-join": "4.0.1",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/auto-instrumentations-node": "^0.53.0",
"@opentelemetry/context-async-hooks": "^1.29.0",
"@opentelemetry/sdk-metrics": "^1.28.0",
"@opentelemetry/sdk-node": "^0.55.0",
"@opentelemetry/sdk-trace-node": "^1.28.0",
"@traceloop/ai-semantic-conventions": "^0.11.0",
"@traceloop/instrumentation-anthropic": "^0.11.1",
"@traceloop/instrumentation-cohere": "^0.11.1",
"@traceloop/instrumentation-openai": "^0.11.3",
"form-data": "^4.0.0",
"form-data-encoder": "^4.0.2",
"formdata-node": "^6.0.3",
"node-fetch": "2.7.0",
"qs": "6.11.2",
"readable-stream": "^4.5.2",
"form-data-encoder": "^4.0.2"
"ts-json-schema-generator": "^2.3.0",
"url-join": "4.0.1",
"uuid": "^11.0.3",
"yarn": "^1.22.22"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"yarn": "^1.22.22"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack fixed

},
"devDependencies": {
"@types/url-join": "4.0.1",
"@types/qs": "6.9.8",
"@anthropic-ai/sdk": "^0.32.1",
"@types/jest": "29.5.5",
"@types/node": "17.0.33",
"@types/node-fetch": "2.6.9",
"@types/qs": "6.9.8",
"@types/readable-stream": "^4.0.15",
"@types/url-join": "4.0.1",
"cohere-ai": "^7.15.0",
"dotenv": "^16.4.6",
"fetch-mock-jest": "^1.5.1",
"webpack": "^5.94.0",
"ts-loader": "^9.3.1",
"jest": "29.7.0",
"@types/jest": "29.5.5",
"ts-jest": "29.1.1",
"jest-environment-jsdom": "29.7.0",
"@types/node": "17.0.33",
"jsonschema": "^1.4.1",
"openai": "^4.74.0",
"prettier": "2.7.1",
"typescript": "4.6.4"
"prettier-plugin-organize-imports": "^4.1.0",
"ts-jest": "29.1.1",
"ts-loader": "^9.3.1",
"typescript": "4.6.4",
"webpack": "^5.94.0"
},
"browser": {
"fs": false,
Expand Down
22 changes: 22 additions & 0 deletions src/eval_utils/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface EvaluationContext {
/** Context Log to Humanloop.
* Per datapoint state that is set when an Evaluation is run.
*/

/** Required for associating a Log with the Evaluation Run. */
source_datapoint_id: string;

/** Overloaded .log method call. */
upload_callback: (log: string) => void;

/** ID of the evaluated File. */
file_id: string;

/** Path of the evaluated File. */
path: string;

/** Required for associating a Log with the Evaluation Run. */
run_id: string;
}

export const EVALUATION_CONTEXT_VARIABLE_NAME = "__EVALUATION_CONTEXT";
1 change: 1 addition & 0 deletions src/eval_utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./context";
93 changes: 93 additions & 0 deletions src/humanloop.client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { NodeTracerProvider, Tracer } from "@opentelemetry/sdk-trace-node";
import { AnthropicInstrumentation } from "@traceloop/instrumentation-anthropic";
import { CohereInstrumentation } from "@traceloop/instrumentation-cohere";
import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai";
import { FlowKernelRequest } from "./api/types/FlowKernelRequest";
import { ToolKernelRequest } from "./api/types/ToolKernelRequest";
import { HumanloopClient as BaseHumanloopClient } from "./Client";
import { HumanloopSpanExporter } from "./otel/exporter";
import { moduleIsInstalled } from "./otel/helpers";
import { HumanloopSpanProcessor } from "./otel/processor";
import { flowUtilityFactory } from "./utilities/flow";
import { promptUtilityFactory, UtilityPromptKernel } from "./utilities/prompt";
import { toolUtilityFactory } from "./utilities/tool";

export class HumanloopClient extends BaseHumanloopClient {
protected readonly opentelemetryTracerProvider: NodeTracerProvider;
protected readonly opentelemetryTracer: Tracer;

constructor(_options: BaseHumanloopClient.Options) {
super(_options);

this.opentelemetryTracerProvider = new NodeTracerProvider({
spanProcessors: [new HumanloopSpanProcessor(new HumanloopSpanExporter(this))],
});

if (moduleIsInstalled("openai")) {
const openai = require("openai").default;
const instrumentor = new OpenAIInstrumentation({ enrichTokens: true });
instrumentor.manuallyInstrument(openai);
instrumentor.setTracerProvider(this.opentelemetryTracerProvider);
instrumentor.enable();
}

if (moduleIsInstalled("@anthropic-ai/sdk")) {
const anthropic = require("@anthropic-ai/sdk");
const instrumentor = new AnthropicInstrumentation();
instrumentor.manuallyInstrument(anthropic);
instrumentor.setTracerProvider(this.opentelemetryTracerProvider);
instrumentor.enable();
}

if (moduleIsInstalled("cohere-ai")) {
const cohere = require("cohere-ai");
const instrumentor = new CohereInstrumentation();
instrumentor.manuallyInstrument(cohere);
instrumentor.setTracerProvider(this.opentelemetryTracerProvider);
instrumentor.enable();
}

this.opentelemetryTracerProvider.register();

this.opentelemetryTracer = this.opentelemetryTracerProvider.getTracer("humanloop.sdk");
}

public prompt<T extends (...args: any[]) => any>(promptUtilityArguments: {
callable: T;
promptKernel?: UtilityPromptKernel;
path?: string;
}) {
return promptUtilityFactory(
this.opentelemetryTracer,
promptUtilityArguments.callable,
promptUtilityArguments.promptKernel,
promptUtilityArguments.path
);
}

public tool<T extends (...args: any[]) => any>(toolUtilityArguments: {
callable: T;
toolKernel: ToolKernelRequest;
path?: string;
}) {
return toolUtilityFactory(
this.opentelemetryTracer,
toolUtilityArguments.callable,
toolUtilityArguments.toolKernel,
toolUtilityArguments.path
);
}

public flow<T extends (...args: any[]) => any>(flowUtilityArguments: {
callable: T;
flowKernel?: FlowKernelRequest;
path?: string;
}) {
return flowUtilityFactory(
this.opentelemetryTracer,
flowUtilityArguments.callable,
flowUtilityArguments.flowKernel,
flowUtilityArguments.path
);
}
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * as Humanloop from "./api";
export { HumanloopClient } from "./Client";
export { HumanloopClient } from "./humanloop.client";
export { HumanloopEnvironment } from "./environments";
export { HumanloopError, HumanloopTimeoutError } from "./errors";
10 changes: 10 additions & 0 deletions src/otel/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Attribute name prefix on Humanloop spans for file-related attributes + path
export const HUMANLOOP_FILE_KEY = "humanloop.file";
// Attribute name prefix on Humanloop spans for log-related attributes
export const HUMANLOOP_LOG_KEY = "humanloop.log";
export const HUMANLOOP_FILE_TYPE_KEY = "humanloop.file_type";
export const HUMANLOOP_PATH_KEY = "humanloop.file.path";
export const HUMANLOOP_PARENT_SPAN_CTX_KEY = "humanloop.context.parentSpanId";
export const HUMANLOOP_TRACE_FLOW_CTX_KEY = "humanloop.context.traceFlow";

export type AsyncFunction = (...args: unknown[]) => Promise<unknown>;
Loading