@handlebar/governance-schema 0.1.1-beta.1 → 0.3.0-dev.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/README.md +86 -16
- package/dist/index.js +119 -38
- package/dist/rules/condition.d.ts +119 -1365
- package/dist/rules/index.d.ts +5 -4
- package/dist/rules/metrics.d.ts +2 -1
- package/dist/rules/rule.d.ts +2 -1796
- package/dist/rules/sensitive.d.ts +136 -0
- package/dist/rules/time.d.ts +5 -2
- package/dist/rules/tools.d.ts +55 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,24 +1,94 @@
|
|
|
1
|
-
# Handlebar
|
|
1
|
+
# Handlebar, Agent Control Layer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[Handlebar] is a runtime control layer for your AI agents.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Enforce deterministic rules on your agents as they act,
|
|
6
|
+
so you can guarantee they don't violate your team's policies.
|
|
6
7
|
|
|
7
|
-
This package
|
|
8
|
-
such as [ai-sdk-v5](https://github.com/gethandlebar/handlebar-js/blob/main/packages/ai-sdk-v5/).
|
|
9
|
-
Refer to that package's README for more information.
|
|
8
|
+
This package provides the policy and event types that Handlebar manages.
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
| Without Handlebar | With Handlebar |
|
|
11
|
+
|:------|:------|
|
|
12
|
+
| "Whoops the agent deleted prod DB" | Deterministically block dangerous tool actions. Full auditability into what your agent _tried_ to do. |
|
|
13
|
+
| "Our costs are ballooning with no way to control them" | Track token usage and USD spend, and set hard limits on your agents. When the limit is reached, Handlebar can block the agent from taking further actions. |
|
|
14
|
+
| "Someone convinced the agent to leak another user's emails" | Limit tool permissions to the user. |
|
|
15
|
+
| "The agent is going off-the-rails and spamming heavy APIs" | Set rate limits on tool use and prevent runaway actions |
|
|
16
|
+
| "We can't be sure the agent isn't leaking sensitive data" | Enforce hard data boundaries between tools and your output. Filter PII before it leaks through agent context |
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
Please refer to [CONTRIBUTING.md][root_contributing]
|
|
15
|
-
for ways you can help,
|
|
16
|
-
and guidelines.
|
|
18
|
+
## Features
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
- Collects auditable event logs of your agent's actions
|
|
21
|
+
- Block dangerous tools use (e.g. `send_email(internalAddress) -> PASS | send_email(unknownperson@randomaddress.ru) -> BLOCK`)
|
|
22
|
+
- Block dangerous tool chaining (e.g. `get_pii` -> `send_slack_message -> BLOCK: risk of data exfil`)
|
|
23
|
+
- Require human reviews on dangerous actions
|
|
24
|
+
- Enforce hard cost budgets and token usage limits for your agents
|
|
25
|
+
- Track usage from each enduser and enforce per-user budgets
|
|
26
|
+
- Rate limit agent actions
|
|
19
27
|
|
|
20
|
-
|
|
28
|
+
## How it works
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
[
|
|
24
|
-
|
|
30
|
+
1. Wrap a Handlebar client (this codebase) around your agent
|
|
31
|
+
1. The client sends event logs of your agent's actions to the [Handlebar platform][platform], where you can analyse them
|
|
32
|
+
1. As your agent receives an action from the LLM, Handlebar intercepts and evaluates the proposed action against your configured policies
|
|
33
|
+
1. If there are violations, Handlebar either permits the action, blocks it, or exits the run
|
|
34
|
+
|
|
35
|
+
## Get started
|
|
36
|
+
|
|
37
|
+
You will need:
|
|
38
|
+
|
|
39
|
+
- an agent...
|
|
40
|
+
- Wrap your agent with a Handlebar client
|
|
41
|
+
- Connect to the [Handlebar platform][platform]
|
|
42
|
+
- Configure policies to enforce on your agent
|
|
43
|
+
|
|
44
|
+
### Wrap your agent with Handlebar
|
|
45
|
+
|
|
46
|
+
This repository is a monorepo containing installable packages
|
|
47
|
+
for different JS/TS agent building frameworks. We provide some pre-built wrappers for agent frameworks,
|
|
48
|
+
with more on the way soon. If your agent is not directly supported, you can still easily plug Handlebar into your agent.
|
|
49
|
+
|
|
50
|
+
| Framework | Install command | Where to read more |
|
|
51
|
+
|:---:|:---:|:---:|
|
|
52
|
+
| Vercel ai **Version 5** | `bun i @handlebar/ai-sdk-v5` | [Vercel AI integration guide](../docs/integrations/vercel-ai-sdk.md) |
|
|
53
|
+
| Vercel ai **Version >=6** | Soon... | |
|
|
54
|
+
| Langchain | Soon... it's still being tested 😕 | See the [langchain integration guide](../docs/integrations/langchain.md) |
|
|
55
|
+
| Openai agents | `bun i @handlebar/core` | See the [OpenAI integration guide](../docs/integrations/openai-agents.md)
|
|
56
|
+
| Other JS/TS, and custom agents | `bun i @handlebar/core` | [`packages/core`](../packages/core) |
|
|
57
|
+
| Python agents | Soon... | |
|
|
58
|
+
|
|
59
|
+
### Connect your agent to the Handlebar platform
|
|
60
|
+
|
|
61
|
+
The client SDKs interact with the Handlebar API to emit agent telemetry and event data it collects,
|
|
62
|
+
and to evaluate your configured policies.
|
|
63
|
+
|
|
64
|
+
Sign up at [`https://app.gethandlebar.com`][platform].\
|
|
65
|
+
If you are waitlisted, [get in touch](#get-in-touch) with us to get access.
|
|
66
|
+
|
|
67
|
+
Once on the platform, create an API key and activate your agent by setting the `HANDLEBAR_API_KEY` environment variable.
|
|
68
|
+
|
|
69
|
+
### Configure policies to enforce on your agent
|
|
70
|
+
|
|
71
|
+
On the [platform] you can create policies from simple templates: usage limits, dangerous tool use, GDPR, finance agents, and more.
|
|
72
|
+
|
|
73
|
+
Alternatively, run the Handlebar claude code skill to generate rules custom to your agent, by running:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx skills add gethandlebar/agent-skills
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Go to the [skill repository](https://github.com/gethandlebar/agent-skills)
|
|
80
|
+
for full instructions.
|
|
81
|
+
|
|
82
|
+
## Get in touch
|
|
83
|
+
|
|
84
|
+
Please [open an issue](https://github.com/gethandlebar/handlebar-js/issues/new) if you have any feedback, suggestions, or requests for framework support.
|
|
85
|
+
Alternatively, [book a call][calendar] to talk to us about how Handlebar could help to protect your team's agents.
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
Apache 2.0 [`LICENSE`](../LICENSE).
|
|
90
|
+
|
|
91
|
+
[handlebar]: https://www.gethandlebar.com
|
|
92
|
+
[platform]: https://app.gethandlebar.com
|
|
93
|
+
[calendar]: https://calendly.com/arjun-handlebar/30min
|
|
94
|
+
[docs]: https://handlebar.mintlify.app
|
package/dist/index.js
CHANGED
|
@@ -13785,12 +13785,7 @@ var RunStartedEventSchema = AuditEnvelopeSchema.extend({
|
|
|
13785
13785
|
var RunEndedEventSchema = AuditEnvelopeSchema.extend({
|
|
13786
13786
|
kind: exports_external.literal("run.ended"),
|
|
13787
13787
|
data: exports_external.object({
|
|
13788
|
-
status: exports_external.enum([
|
|
13789
|
-
"error",
|
|
13790
|
-
"success",
|
|
13791
|
-
"timeout",
|
|
13792
|
-
"interrupted"
|
|
13793
|
-
]),
|
|
13788
|
+
status: exports_external.enum(["error", "success", "timeout", "interrupted"]),
|
|
13794
13789
|
totalSteps: exports_external.number().min(0),
|
|
13795
13790
|
summary: exports_external.string().optional()
|
|
13796
13791
|
})
|
|
@@ -13886,10 +13881,10 @@ var MetricRefSchema = exports_external.discriminatedUnion("kind", [
|
|
|
13886
13881
|
]);
|
|
13887
13882
|
var MetricWindowConditionSchema = exports_external.object({
|
|
13888
13883
|
kind: exports_external.literal("metricWindow"),
|
|
13889
|
-
scope: exports_external.enum(["agent", "agent_user"]),
|
|
13884
|
+
scope: exports_external.enum(["run", "agent", "agent_user"]),
|
|
13890
13885
|
metric: MetricRefSchema,
|
|
13891
13886
|
aggregate: exports_external.enum(["sum", "avg", "max", "min", "count"]),
|
|
13892
|
-
windowSeconds: exports_external.number().int().positive(),
|
|
13887
|
+
windowSeconds: exports_external.number().int().positive().optional(),
|
|
13893
13888
|
filter: exports_external.object({
|
|
13894
13889
|
toolName: exports_external.union([GlobSchema, exports_external.array(GlobSchema).min(1)]).optional(),
|
|
13895
13890
|
toolTag: exports_external.union([exports_external.string().min(1), exports_external.array(exports_external.string().min(1)).min(1)]).optional()
|
|
@@ -13899,6 +13894,53 @@ var MetricWindowConditionSchema = exports_external.object({
|
|
|
13899
13894
|
onMissing: RuleEffectKindSchema.optional()
|
|
13900
13895
|
}).strict();
|
|
13901
13896
|
|
|
13897
|
+
// src/rules/sensitive.ts
|
|
13898
|
+
var SensitiveDataDetectorSchema = exports_external.enum([
|
|
13899
|
+
"email",
|
|
13900
|
+
"email_domain",
|
|
13901
|
+
"phone",
|
|
13902
|
+
"credit_card",
|
|
13903
|
+
"iban",
|
|
13904
|
+
"uk_nino",
|
|
13905
|
+
"ip_address",
|
|
13906
|
+
"url",
|
|
13907
|
+
"jwt",
|
|
13908
|
+
"private_key",
|
|
13909
|
+
"secret_key"
|
|
13910
|
+
]);
|
|
13911
|
+
var SubConditionValueSchema = exports_external.union([
|
|
13912
|
+
exports_external.string().min(1),
|
|
13913
|
+
exports_external.array(exports_external.string().min(1)).min(1)
|
|
13914
|
+
]);
|
|
13915
|
+
var SensitiveDataSubConditionSchema = exports_external.discriminatedUnion("check", [
|
|
13916
|
+
exports_external.object({
|
|
13917
|
+
check: exports_external.literal("domain"),
|
|
13918
|
+
op: exports_external.enum(["eq", "neq", "endsWith", "in"]),
|
|
13919
|
+
value: SubConditionValueSchema
|
|
13920
|
+
}).strict(),
|
|
13921
|
+
exports_external.object({
|
|
13922
|
+
check: exports_external.literal("tld"),
|
|
13923
|
+
op: exports_external.enum(["eq", "neq", "in"]),
|
|
13924
|
+
value: SubConditionValueSchema
|
|
13925
|
+
}).strict(),
|
|
13926
|
+
exports_external.object({
|
|
13927
|
+
check: exports_external.literal("scheme"),
|
|
13928
|
+
op: exports_external.enum(["eq", "neq", "in"]),
|
|
13929
|
+
value: SubConditionValueSchema
|
|
13930
|
+
}).strict()
|
|
13931
|
+
]);
|
|
13932
|
+
var SensitiveDataDetectorEntrySchema = exports_external.object({
|
|
13933
|
+
detector: SensitiveDataDetectorSchema,
|
|
13934
|
+
subCondition: SensitiveDataSubConditionSchema.optional()
|
|
13935
|
+
}).strict();
|
|
13936
|
+
var SensitiveDataConditionSchema = exports_external.object({
|
|
13937
|
+
kind: exports_external.literal("sensitiveData"),
|
|
13938
|
+
target: exports_external.literal("toolArg"),
|
|
13939
|
+
path: exports_external.string().min(1).max(200).optional(),
|
|
13940
|
+
op: exports_external.enum(["anyOf", "allOf"]).default("anyOf"),
|
|
13941
|
+
detectors: exports_external.array(SensitiveDataDetectorEntrySchema).min(1)
|
|
13942
|
+
}).strict();
|
|
13943
|
+
|
|
13902
13944
|
// src/rules/signals.ts
|
|
13903
13945
|
var RequireSubjectConditionSchema = exports_external.object({
|
|
13904
13946
|
kind: exports_external.literal("requireSubject"),
|
|
@@ -13931,13 +13973,20 @@ var SignalConditionSchema = exports_external.object({
|
|
|
13931
13973
|
// src/rules/time.ts
|
|
13932
13974
|
var DaySchema = exports_external.enum(["mon", "tue", "wed", "thu", "fri", "sat", "sun"]);
|
|
13933
13975
|
var TimeHHMMSchema = exports_external.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, 'Expected time in "HH:MM" 24-hour format');
|
|
13934
|
-
var
|
|
13935
|
-
|
|
13936
|
-
timezone: exports_external.object({
|
|
13976
|
+
var TimezoneSchema = exports_external.discriminatedUnion("source", [
|
|
13977
|
+
exports_external.object({
|
|
13937
13978
|
source: exports_external.literal("enduserTag"),
|
|
13938
13979
|
tag: exports_external.string().min(1),
|
|
13939
13980
|
fallback: exports_external.literal("org").optional()
|
|
13940
13981
|
}).strict(),
|
|
13982
|
+
exports_external.object({
|
|
13983
|
+
source: exports_external.literal("static"),
|
|
13984
|
+
tz: exports_external.string().min(1)
|
|
13985
|
+
}).strict()
|
|
13986
|
+
]);
|
|
13987
|
+
var TimeGateConditionSchema = exports_external.object({
|
|
13988
|
+
kind: exports_external.literal("timeGate"),
|
|
13989
|
+
timezone: TimezoneSchema,
|
|
13941
13990
|
windows: exports_external.array(exports_external.object({
|
|
13942
13991
|
days: exports_external.array(DaySchema).min(1),
|
|
13943
13992
|
start: TimeHHMMSchema,
|
|
@@ -13965,28 +14014,43 @@ var ToolNameConditionSchema = exports_external.discriminatedUnion("op", [
|
|
|
13965
14014
|
value: exports_external.array(exports_external.string().min(1)).min(1)
|
|
13966
14015
|
}).strict()
|
|
13967
14016
|
]);
|
|
13968
|
-
var ToolArgConditionSchema = exports_external.
|
|
13969
|
-
exports_external.
|
|
13970
|
-
|
|
13971
|
-
|
|
13972
|
-
|
|
13973
|
-
|
|
13974
|
-
|
|
13975
|
-
|
|
13976
|
-
|
|
13977
|
-
|
|
13978
|
-
|
|
13979
|
-
|
|
13980
|
-
|
|
13981
|
-
|
|
13982
|
-
|
|
14017
|
+
var ToolArgConditionSchema = exports_external.union([
|
|
14018
|
+
exports_external.discriminatedUnion("type", [
|
|
14019
|
+
exports_external.object({
|
|
14020
|
+
kind: exports_external.literal("toolArg"),
|
|
14021
|
+
type: exports_external.literal("string"),
|
|
14022
|
+
op: exports_external.enum([
|
|
14023
|
+
"eq",
|
|
14024
|
+
"neq",
|
|
14025
|
+
"contains",
|
|
14026
|
+
"startsWith",
|
|
14027
|
+
"endsWith",
|
|
14028
|
+
"in",
|
|
14029
|
+
"regex"
|
|
14030
|
+
]),
|
|
14031
|
+
path: exports_external.string().min(1).max(100).optional(),
|
|
14032
|
+
value: exports_external.string().min(1).max(1000)
|
|
14033
|
+
}),
|
|
14034
|
+
exports_external.object({
|
|
14035
|
+
kind: exports_external.literal("toolArg"),
|
|
14036
|
+
type: exports_external.literal("number"),
|
|
14037
|
+
op: exports_external.enum(["eq", "neq", "lt", "lte", "gt", "gte"]),
|
|
14038
|
+
path: exports_external.string().min(1).max(100).optional(),
|
|
14039
|
+
value: exports_external.number()
|
|
14040
|
+
}),
|
|
14041
|
+
exports_external.object({
|
|
14042
|
+
kind: exports_external.literal("toolArg"),
|
|
14043
|
+
type: exports_external.literal("boolean"),
|
|
14044
|
+
op: exports_external.literal("eq"),
|
|
14045
|
+
path: exports_external.string().min(1).max(100).optional(),
|
|
14046
|
+
value: exports_external.boolean()
|
|
14047
|
+
})
|
|
14048
|
+
]),
|
|
13983
14049
|
exports_external.object({
|
|
13984
14050
|
kind: exports_external.literal("toolArg"),
|
|
13985
|
-
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
value: exports_external.boolean()
|
|
13989
|
-
})
|
|
14051
|
+
op: exports_external.enum(["exists", "notExists"]),
|
|
14052
|
+
path: exports_external.string().min(1).max(100)
|
|
14053
|
+
}).strict()
|
|
13990
14054
|
]);
|
|
13991
14055
|
var ToolTagConditionSchema = exports_external.discriminatedUnion("op", [
|
|
13992
14056
|
exports_external.object({
|
|
@@ -14005,10 +14069,22 @@ var ToolTagConditionSchema = exports_external.discriminatedUnion("op", [
|
|
|
14005
14069
|
tags: exports_external.array(exports_external.string().min(1)).min(1)
|
|
14006
14070
|
}).strict()
|
|
14007
14071
|
]);
|
|
14072
|
+
var SequenceEntrySchema = exports_external.union([
|
|
14073
|
+
GlobSchema,
|
|
14074
|
+
exports_external.object({
|
|
14075
|
+
by: exports_external.literal("toolName"),
|
|
14076
|
+
patterns: exports_external.array(GlobSchema).min(1)
|
|
14077
|
+
}).strict(),
|
|
14078
|
+
exports_external.object({
|
|
14079
|
+
by: exports_external.literal("toolTag"),
|
|
14080
|
+
tags: exports_external.array(exports_external.string().min(1)).min(1),
|
|
14081
|
+
op: exports_external.enum(["anyOf", "allOf"]).optional()
|
|
14082
|
+
}).strict()
|
|
14083
|
+
]);
|
|
14008
14084
|
var SequenceConditionSchema = exports_external.object({
|
|
14009
14085
|
kind: exports_external.literal("sequence"),
|
|
14010
|
-
mustHaveCalled: exports_external.array(
|
|
14011
|
-
mustNotHaveCalled: exports_external.array(
|
|
14086
|
+
mustHaveCalled: exports_external.array(SequenceEntrySchema).min(1).optional(),
|
|
14087
|
+
mustNotHaveCalled: exports_external.array(SequenceEntrySchema).min(1).optional()
|
|
14012
14088
|
}).strict().refine((v) => v.mustHaveCalled?.length || v.mustNotHaveCalled?.length, "sequence requires mustHaveCalled and/or mustNotHaveCalled");
|
|
14013
14089
|
var MaxCallsSelectorSchema = exports_external.discriminatedUnion("by", [
|
|
14014
14090
|
exports_external.object({ by: exports_external.literal("toolName"), patterns: exports_external.array(GlobSchema).min(1) }).strict(),
|
|
@@ -14020,7 +14096,10 @@ var MaxCallsSelectorSchema = exports_external.discriminatedUnion("by", [
|
|
|
14020
14096
|
var MaxCallsConditionSchema = exports_external.object({
|
|
14021
14097
|
kind: exports_external.literal("maxCalls"),
|
|
14022
14098
|
selector: MaxCallsSelectorSchema,
|
|
14023
|
-
max: exports_external.number().int().nonnegative()
|
|
14099
|
+
max: exports_external.number().int().nonnegative(),
|
|
14100
|
+
windowSeconds: exports_external.number().int().positive().optional(),
|
|
14101
|
+
per: exports_external.enum(["agent", "agent_user"]).optional(),
|
|
14102
|
+
tagFilter: exports_external.array(exports_external.string().min(1)).min(1).optional()
|
|
14024
14103
|
}).strict();
|
|
14025
14104
|
|
|
14026
14105
|
// src/rules/condition.ts
|
|
@@ -14036,17 +14115,19 @@ var BaseRuleConditionSchema = exports_external.union([
|
|
|
14036
14115
|
MetricWindowConditionSchema,
|
|
14037
14116
|
TimeGateConditionSchema,
|
|
14038
14117
|
RequireSubjectConditionSchema,
|
|
14039
|
-
SignalConditionSchema
|
|
14118
|
+
SignalConditionSchema,
|
|
14119
|
+
SensitiveDataConditionSchema
|
|
14040
14120
|
]);
|
|
14121
|
+
var LazyRuleConditionSchema = exports_external.lazy(() => RuleConditionSchema);
|
|
14041
14122
|
var AndConditionSchema = exports_external.object({
|
|
14042
14123
|
kind: exports_external.literal("and"),
|
|
14043
|
-
all: exports_external.array(
|
|
14124
|
+
all: exports_external.array(LazyRuleConditionSchema).min(1)
|
|
14044
14125
|
}).strict();
|
|
14045
14126
|
var OrConditionSchema = exports_external.object({
|
|
14046
14127
|
kind: exports_external.literal("or"),
|
|
14047
|
-
any: exports_external.array(
|
|
14128
|
+
any: exports_external.array(LazyRuleConditionSchema).min(1)
|
|
14048
14129
|
}).strict();
|
|
14049
|
-
var NotConditionSchema = exports_external.object({ kind: exports_external.literal("not"), not:
|
|
14130
|
+
var NotConditionSchema = exports_external.object({ kind: exports_external.literal("not"), not: LazyRuleConditionSchema }).strict();
|
|
14050
14131
|
var RuleConditionSchema = exports_external.union([
|
|
14051
14132
|
BaseRuleConditionSchema,
|
|
14052
14133
|
AndConditionSchema,
|