wip on humanlayer-ts example

This commit is contained in:
dexhorthy
2024-09-11 17:07:54 -05:00
parent d4f354e1f3
commit 5f4cc9f67f
18 changed files with 2023 additions and 97 deletions

View File

@@ -0,0 +1,56 @@
"use strict";
var __awaiter =
(this && this.__awaiter) ||
function (thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P
? value
: new P(function (resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done
? resolve(result.value)
: adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const openai_1 = __importDefault(require("openai"));
const openAIHello = () =>
__awaiter(void 0, void 0, void 0, function* () {
const openai = new openai_1.default({
apiKey: process.env.OPENAI_API_KEY,
});
const response = yield openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello, world!" }],
});
});
const main = () =>
__awaiter(void 0, void 0, void 0, function* () {
yield openAIHello();
});
main().then(console.log).catch(console.error);

View File

@@ -1,18 +1,98 @@
import { HumanLayer } from "humanlayer";
import { FunctionCallSpec } from "humanlayer";
import OpenAI from "openai";
import { ChatCompletionTool } from "openai/src/resources/index.js";
const PROMPT = "multiply 2 and 5, then add 32 to the result";
const openAIHello = async () => {
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
const multiply = ({ a, b }: { a: number; b: number }) => a * b;
const add = ({ a, b }: { a: number; b: number }) => a + b;
const response = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [{ role: "user", content: "Hello, world!" }],
});
const tools_map = {
multiply: multiply,
add: add,
};
openAIHello().catch(console.error);
const openai_tools: ChatCompletionTool[] = [
{
type: "function",
function: {
name: "multiply",
description: "multiply two numbers",
parameters: {
type: "object",
properties: {
a: { type: "number" },
b: { type: "number" },
},
required: ["a", "b"],
},
},
},
{
type: "function",
function: {
name: "add",
description: "add two numbers",
parameters: {
type: "object",
properties: {
a: { type: "number" },
b: { type: "number" },
},
required: ["a", "b"],
},
},
},
];
const openAIHello = async (
prompt: string,
tools_map: { [key: string]: (args: any) => any },
openai_tools: ChatCompletionTool[],
) => {
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
const messages: any[] = [{ role: "user", content: prompt }];
let response = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: messages,
tools: openai_tools,
tool_choice: "auto",
});
while (response.choices[0].message.tool_calls) {
messages.push(response.choices[0].message);
const tool_calls = response.choices[0].message.tool_calls;
for (const tool_call of tool_calls) {
const tool_name = tool_call.function.name;
const tool_args = JSON.parse(tool_call.function.arguments);
console.log(
`calling tools ${tool_name}(${tool_call.function.arguments})`,
);
const tool_result = tools_map[tool_name](tool_args);
messages.push({
role: "tool",
name: tool_name,
content: JSON.stringify(tool_result),
tool_call_id: tool_call.id,
});
}
response = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: messages,
});
}
return response.choices[0].message.content;
};
const main = async (): Promise<any> => {
const resp = await openAIHello(PROMPT, tools_map, openai_tools);
return resp;
};
main().then(console.log).catch(console.error);

1229
examples/ts_openai_client/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,9 +3,10 @@
"version": "0.1.0",
"description": "example of using humanlayer with openai in typescript",
"main": "index.ts",
"type": "module",
"scripts": {
"build": "tsc",
"dev": "node --env-file=.env -r ts-node/register index.ts"
"dev": "tsx --env-file=.env index.ts"
},
"repository": {
"type": "git",
@@ -26,6 +27,7 @@
"devDependencies": {
"@types/node": "^20.14.9",
"ts-node": "^10.9.2",
"tsx": "^4.19.0",
"typescript": "^5.5.2"
}
}

View File

@@ -0,0 +1,21 @@
# HumanLayer example using OpenAI client in Typescript
Set up env
```
cp dotenv.example .env
# configure API token(s)
```
## Running with NPM
```
npm install
npm run dev
```
## If you prefer docker
```
docker compose run examples
```

View File

@@ -0,0 +1,12 @@
{
"include": ["**/*.ts"],
"exclude": ["node_modules"],
"compilerOptions": {
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"module": "commonjs" /* Specify what module code is generated. */,
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
"strict": true /* Enable all strict type-checking options. */,
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

View File

@@ -1,9 +1,7 @@
{
"$schema": "https://json.schemastore.org/eslintrc",
"root": true,
"extends": [
"prettier"
],
"extends": ["prettier"],
"overrides": [
{
"files": ["*.ts", "*.tsx"],

View File

@@ -33,4 +33,4 @@ yarn-error.log*
.turbo
.contentlayer
.env
.env

View File

@@ -9,4 +9,4 @@ dist
node_modules
.next
build
.contentlayer
.contentlayer

View File

@@ -0,0 +1,377 @@
import crypto from 'crypto'
import { AgentBackend, HumanLayerException } from './protocol'
import {
ContactChannel,
FunctionCall,
FunctionCallSpec,
HumanContact,
HumanContactSpec,
} from './models'
import { CloudHumanLayerBackend, HumanLayerCloudConnection } from './cloud'
import { logger } from './logger'
export enum ApprovalMethod {
CLI = 'cli',
BACKEND = 'backend',
}
/**
* sure this'll work for now
*/
export const default_genid = (prefix: string) => {
return `${prefix}-${crypto.randomUUID().slice(0, 8)}`
}
export class HumanLayer {
approval_method: ApprovalMethod
backend?: AgentBackend
run_id: string
agent_name: string
genid: (prefix: string) => string
sleep: (ms: number) => Promise<void>
contact_channel?: ContactChannel
constructor({
run_id,
approval_method,
backend,
agent_name,
genid,
sleep,
contact_channel,
api_key,
api_base_url,
}: {
run_id?: string
approval_method?: ApprovalMethod
backend?: AgentBackend
agent_name?: string
genid?: (prefix: string) => string
sleep?: (ms: number) => Promise<void>
contact_channel?: ContactChannel
api_key?: string
api_base_url?: string
}) {
this.genid = genid || default_genid
this.sleep = sleep || (ms => new Promise(resolve => setTimeout(resolve, ms)))
this.contact_channel = contact_channel
if (!approval_method && process.env.HUMANLAYER_APPROVAL_METHOD) {
const method = process.env.HUMANLAYER_APPROVAL_METHOD as keyof typeof ApprovalMethod
if (method in ApprovalMethod) {
this.approval_method = ApprovalMethod[method]
} else {
throw new Error(`Invalid HUMANLAYER_APPROVAL_METHOD: ${process.env.HUMANLAYER_APPROVAL_METHOD}`)
}
}
if (!approval_method) {
if (backend || process.env.HUMANLAYER_API_KEY) {
this.approval_method = ApprovalMethod.BACKEND
this.backend =
backend ||
new CloudHumanLayerBackend(
new HumanLayerCloudConnection(
api_key || process.env.HUMANLAYER_API_KEY,
api_base_url || process.env.HUMANLAYER_API_BASE_URL,
),
)
} else {
logger.info('No HUMANLAYER_API_KEY found, defaulting to CLI approval')
this.approval_method = ApprovalMethod.CLI
}
} else {
this.approval_method = approval_method
}
this.agent_name = agent_name || 'agent'
this.genid = genid || default_genid
this.run_id = run_id || this.genid(this.agent_name)
if (this.approval_method === ApprovalMethod.BACKEND && !backend) {
throw new HumanLayerException('backend is required for non-cli approvals')
}
this.backend = backend
}
static cloud({
connection,
api_key,
api_base_url,
}: {
connection: HumanLayerCloudConnection | null
api_key?: string
api_base_url?: string
}): HumanLayer {
if (!connection) {
connection = new HumanLayerCloudConnection(api_key, api_base_url)
}
return new HumanLayer({
approval_method: ApprovalMethod.BACKEND,
backend: new CloudHumanLayerBackend(connection),
})
}
static cli(): HumanLayer {
return new HumanLayer({
approval_method: ApprovalMethod.CLI,
})
}
require_approval<T_Fn extends Function>(contact_channel?: ContactChannel): (fn: T_Fn) => T_Fn {
return (fn: T_Fn) => {
if (this.approval_method === ApprovalMethod.CLI) {
return this._approve_cli(fn)
}
return this._approve_with_backend(fn, contact_channel)
}
}
_approve_cli<T_Fn extends Function>(fn: T_Fn): T_Fn {
// todo fix the types here
const f: any = (...args: any[]) => {
console.log(`Agent ${this.run_id} wants to call
${fn.name}(${JSON.stringify(args, null, 2)})
${args.length ? ' with args: ' + JSON.stringify(args, null, 2) : ''}`)
const feedback = prompt('Hit ENTER to proceed, or provide feedback to the agent to deny: \n\n')
if (feedback !== null && feedback !== '') {
return new Error(`User denied ${fn.name} with feedback: ${feedback}`)
}
try {
return fn(...args)
} catch (e) {
return `Error running ${fn.name}: ${e}`
}
}
f.name = fn.name
return f
}
_approve_with_backend<T_Fn extends Function>(fn: T_Fn, contact_channel?: ContactChannel): T_Fn {
// todo fix the types here
const f: any = async (...args: any[]) => {
const backend = this.backend!
const call_id = this.genid('call')
await backend.functions().add({
run_id: this.run_id,
call_id,
spec: {
fn: fn.name,
kwargs: args,
channel: contact_channel,
},
})
while (true) {
await this.sleep(3000)
const function_call = await backend.functions().get(call_id)
if (function_call.status?.approved) {
return fn(...args)
} else {
return function_call.status?.comment
}
}
}
f.name = fn.name
return f
}
}
/**
class HumanLayer(BaseModel):
"""HumanLayer"""
def require_approval(
self,
contact_channel: ContactChannel | None = None,
) -> HumanLayerWrapper:
def decorator(fn): # type: ignore
if self.approval_method is ApprovalMethod.CLI:
return self._approve_cli(fn)
return self._approve_with_backend(fn, contact_channel)
return HumanLayerWrapper(decorator)
def _approve_cli(self, fn: Callable[[T], R]) -> Callable[[T], R | str]:
"""
NOTE we convert a callable[[T], R] to a Callable [[T], R | str]
this is safe to do for most LLM use cases. It will blow up
a normal function.
If we can guarantee the function calling framework
is properly handling exceptions, then we can
just raise and let the framework handle the stringification
of what went wrong.
Because some frameworks dont handle exceptions well, were stuck with the hack for now
"""
@wraps(fn)
def wrapper(*args, **kwargs) -> R | str: # type: ignore
print(
f"""Agent {self.run_id} wants to call
{fn.__name__}({json.dumps(kwargs, indent=2)})
{"" if not args else " with args: " + str(args)}"""
)
feedback = input("Hit ENTER to proceed, or provide feedback to the agent to deny: \n\n")
if feedback not in {
None,
"",
}:
return str(UserDeniedError(f"User denied {fn.__name__} with feedback: {feedback}"))
try:
return fn(*args, **kwargs)
except Exception as e:
return f"Error running {fn.__name__}: {e}"
return wrapper
def _approve_with_backend(
self,
fn: Callable[[T], R],
contact_channel: ContactChannel | None = None,
) -> Callable[[T], R | str]:
"""
NOTE we convert a callable[[T], R] to a Callable [[T], R | str]
this is safe to do for most LLM use cases. It will blow up
a normal function.
If we can guarantee the function calling framework
is properly handling exceptions, then we can
just raise and let the framework handle the stringification
of what went wrong.
Because some frameworks dont handle exceptions well, were stuck with the hack for now
"""
contact_channel = contact_channel or self.contact_channel
@wraps(fn)
def wrapper(*args, **kwargs) -> R | str: # type: ignore
assert self.backend is not None
call_id = self.genid("call")
try:
call = FunctionCall(
run_id=self.run_id, # type: ignore
call_id=call_id,
spec=FunctionCallSpec(
fn=fn.__name__,
kwargs=kwargs,
channel=contact_channel,
),
)
self.backend.functions().add(call)
# todo lets do a more async-y websocket soon
while True:
self.sleep(3)
function_call: FunctionCall = self.backend.functions().get(call_id)
if function_call.status is None or function_call.status.approved is None:
continue
if function_call.status.approved:
return fn(*args, **kwargs)
else:
if (
function_call.spec.channel
and function_call.spec.channel.slack
and function_call.spec.channel.slack.context_about_channel_or_user
):
return f"User in {function_call.spec.channel.slack.context_about_channel_or_user} denied {fn.__name__} with message: {function_call.status.comment}"
elif (
contact_channel
and contact_channel.slack
and contact_channel.slack.context_about_channel_or_user
):
return f"User in {contact_channel.slack.context_about_channel_or_user} denied {fn.__name__} with message: {function_call.status.comment}"
else:
return f"User denied {fn.__name__} with message: {function_call.status.comment}"
except Exception as e:
logger.exception("Error requesting approval")
# todo - raise vs. catch behavior - many tool clients handle+wrap errors
# but not all of them :rolling_eyes:
return f"Error running {fn.__name__}: {e}"
return wrapper
def human_as_tool(
self,
contact_channel: ContactChannel | None = None,
) -> Callable[[str], str]:
if self.approval_method is ApprovalMethod.CLI:
return self._human_as_tool_cli()
return self._human_as_tool(contact_channel)
def _human_as_tool_cli(
self,
) -> Callable[[str], str]:
def contact_human(
question: str,
) -> str:
"""ask a human a question on the CLI"""
print(
f"""Agent {self.run_id} requests assistance:
{question}
"""
)
feedback = input("Please enter a response: \n\n")
return feedback
return contact_human
def _human_as_tool(
self,
contact_channel: ContactChannel | None = None,
) -> Callable[[str], str]:
contact_channel = contact_channel or self.contact_channel
def contact_human(
message: str,
) -> str:
"""contact a human"""
assert self.backend is not None
call_id = self.genid("human_call")
contact = HumanContact(
run_id=self.run_id, # type: ignore
call_id=call_id,
spec=HumanContactSpec(
msg=message,
channel=contact_channel,
),
)
self.backend.contacts().add(contact)
# todo lets do a more async-y websocket soon
while True:
self.sleep(3)
human_contact = self.backend.contacts().get(call_id)
if human_contact.status is None:
continue
if human_contact.status.response is not None:
return human_contact.status.response
if contact_channel is None:
return contact_human
if contact_channel.slack:
contact_human.__doc__ = "Contact a human via slack and wait for a response"
contact_human.__name__ = "contact_human_in_slack"
if contact_channel.slack.context_about_channel_or_user:
contact_human.__doc__ += f" in {contact_channel.slack.context_about_channel_or_user}"
fn_ctx = contact_channel.slack.context_about_channel_or_user.replace(" ", "_")
contact_human.__name__ = f"contact_human_in_slack_in_{fn_ctx}"
return contact_human
*/

116
humanlayer-ts/src/cloud.ts Normal file
View File

@@ -0,0 +1,116 @@
import { AgentBackend, AgentStore, HumanLayerException } from './protocol'
import { FunctionCall, HumanContact } from './models'
class HumanLayerCloudConnection {
api_key?: string
api_base_url?: string
constructor(api_key?: string, api_base_url?: string) {
this.api_key = api_key
this.api_base_url = api_base_url
if (!this.api_key) {
throw new Error('HUMANLAYER_API_KEY is required for cloud approvals')
}
this.api_base_url = this.api_base_url || 'https://api.humanlayer.dev/humanlayer/v1'
// todo ping api to validate token
}
async request({
method,
path,
body,
}: {
method: string
path: string
body?: any
}): Promise<Response> {
const resp = await fetch(`${this.api_base_url}${path}`, {
method,
headers: {
Authorization: `Bearer ${this.api_key}`,
},
body,
})
if (resp.status >= 400) {
throw new HumanLayerException(`${method} ${path} ${resp.status}: ${await resp.text()}`)
}
return resp
}
}
class CloudFunctionCallStore implements AgentStore<FunctionCall> {
private connection: HumanLayerCloudConnection
constructor(connection: HumanLayerCloudConnection) {
this.connection = connection
}
async add(item: FunctionCall): Promise<void> {
await this.connection.request({
method: 'POST',
path: '/function_calls',
body: JSON.stringify(item),
})
}
async get(call_id: string): Promise<FunctionCall> {
const resp = await this.connection.request({
method: 'GET',
path: `/function_calls/${call_id}`,
})
const data = await resp.json()
return data as FunctionCall
}
}
class CloudHumanContactStore implements AgentStore<HumanContact> {
private connection: HumanLayerCloudConnection
constructor(connection: HumanLayerCloudConnection) {
this.connection = connection
}
async add(item: HumanContact): Promise<void> {
const resp = await this.connection.request({
method: 'POST',
path: '/contact_requests',
body: JSON.stringify(item),
})
}
async get(call_id: string): Promise<HumanContact> {
const resp = await this.connection.request({
method: 'GET',
path: `/contact_requests/${call_id}`,
})
const data = await resp.json()
return data as HumanContact
}
}
class CloudHumanLayerBackend implements AgentBackend {
private _function_calls: CloudFunctionCallStore
private _human_contacts: CloudHumanContactStore
constructor(connection: HumanLayerCloudConnection) {
this._function_calls = new CloudFunctionCallStore(connection)
this._human_contacts = new CloudHumanContactStore(connection)
}
functions(): CloudFunctionCallStore {
return this._function_calls
}
contacts(): CloudHumanContactStore {
return this._human_contacts
}
}
export {
HumanLayerCloudConnection,
CloudFunctionCallStore,
CloudHumanContactStore,
CloudHumanLayerBackend,
}

View File

@@ -1 +1,3 @@
console.log("sucessfully installed humanlayer-ts")
export * from './models'
export * from './approval'
export * from './cloud'

View File

@@ -0,0 +1,12 @@
// TODO: maybe use a real lib
export const logger = {
debug: (...args: any[]) => {
console.debug(...args)
},
info: (...args: any[]) => {
console.info(...args)
},
error: (...args: any[]) => {
console.error(...args)
},
}

View File

@@ -0,0 +1,69 @@
type FunctionCallStatus = {
requested_at: Date
responded_at?: Date
approved?: boolean
comment?: string
}
type SlackContactChannel = {
// the slack channel or user id to contact
channel_or_user_id: string
// the context about the channel or user to contact
context_about_channel_or_user?: string
// the bot token to use to contact the channel or user
bot_token?: string
}
type ContactChannel = {
slack?: SlackContactChannel
}
type FunctionCallSpec = {
// the function name to call
fn: string
// the function arguments
kwargs: Record<string, any>
// the contact channel to use to contact the human
channel?: ContactChannel
}
type FunctionCall = {
// the run id
run_id: string
call_id: string
spec: FunctionCallSpec
status?: FunctionCallStatus
}
type HumanContactSpec = {
// the message to send to the human
msg: string
// the contact channel to use to contact the human
channel?: ContactChannel
}
type HumanContactStatus = {
// the response from the human
response: string
}
type HumanContact = {
// the run id
run_id: string
// the call id
call_id: string
// the spec for the human contact
spec: HumanContactSpec
status?: HumanContactStatus
}
export {
FunctionCallStatus,
SlackContactChannel,
ContactChannel,
FunctionCallSpec,
FunctionCall,
HumanContactSpec,
HumanContactStatus,
HumanContact,
}

View File

@@ -0,0 +1,23 @@
import { FunctionCall, FunctionCallStatus, HumanContact, HumanContactStatus } from './models'
export type AgentStore<T_Call> = {
add: (item: T_Call) => Promise<void>
get: (call_id: string) => Promise<T_Call>
}
export type AdminStore<T_Call, T_Status> = {
respond: (call_id: string, status: T_Status) => Promise<void>
list: (call_id: string) => Promise<Iterable<T_Call>>
}
export class HumanLayerException extends Error {}
export type AgentBackend = {
functions(): AgentStore<FunctionCall>
contacts(): AgentStore<HumanContact>
}
export type AdminBackend = {
functions(): AdminStore<FunctionCall, FunctionCallStatus>
contacts(): AdminStore<HumanContact, HumanContactStatus>
}

View File

@@ -1,71 +0,0 @@
type FunctionCallStatus = {
requested_at: Date
responded_at: Date | null
approved: boolean | null
comment: string | null
}
type SlackContactChannel = {
// the slack channel or user id to contact
channel_or_user_id: string
// the context about the channel or user to contact
context_about_channel_or_user: string | null
// the bot token to use to contact the channel or user
bot_token: string | null
}
type ContactChannel = {
slack: SlackContactChannel | null
}
type FunctionCallSpec = {
// the function name to call
fn: string
// the function arguments
kwargs: Record<string, any>
// the contact channel to use to contact the human
channel: ContactChannel | null
}
type FunctionCall = {
// the run id
run_id: string
call_id: string
spec: FunctionCallSpec
status: FunctionCallStatus | null
}
type HumanContactSpec = {
// the message to send to the human
msg: string
// the contact channel to use to contact the human
channel: ContactChannel | null
}
type HumanContactStatus = {
// the response from the human
response: string
}
type HumanContact = {
// the run id
run_id: string
// the call id
call_id: string
// the spec for the human contact
spec: HumanContactSpec
status: HumanContactStatus | null
}
export {
FunctionCallStatus,
SlackContactChannel,
ContactChannel,
FunctionCallSpec,
FunctionCall,
HumanContactSpec,
HumanContactStatus,
HumanContact,
}

View File

@@ -11,7 +11,7 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
@@ -25,7 +25,7 @@
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
"module": "commonjs" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
@@ -71,12 +71,12 @@
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
@@ -98,6 +98,6 @@
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

View File

@@ -133,7 +133,7 @@ max-complexity = 12
line_length = 104
[tool.deptry]
exclude = ["examples", "venv", ".venv"]
exclude = ["examples", "venv", ".venv", "humanlayer-ts"]
[tool.deptry.per_rule_ignores]