@ethogram/core 0.1.0-alpha.0 → 0.1.0-alpha.2
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 +61 -12
- package/dist/index.cjs +26 -3
- package/dist/index.js +26 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,23 +1,72 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@ethogram/core`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
TypeScript contracts for writing Ethogram Agent descriptors, Stories, behavioral expectations, and local execution profiles.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> Public alpha `0.1.0-alpha.2`. APIs may change between `0.x` releases. Node.js 20.9 or newer is required.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Install
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Most projects install core together with the CLI:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install --save-dev @ethogram/core@next @ethogram/cli@next
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The project imports `@ethogram/core` directly. The CLI supplies `ethogram init` and the local developer interface.
|
|
16
|
+
|
|
17
|
+
## Write a Story
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { defineAgent, defineStory } from '@ethogram/core'
|
|
21
|
+
|
|
22
|
+
const accessAgent = defineAgent({
|
|
23
|
+
id: 'access-agent',
|
|
24
|
+
name: 'Access Agent',
|
|
25
|
+
description: 'Handles access requests.',
|
|
26
|
+
icon: 'target',
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
export const adminAccessRequiresApproval = defineStory({
|
|
30
|
+
id: 'admin-access-requires-approval',
|
|
31
|
+
name: 'Admin Access Requires Approval',
|
|
32
|
+
agent: accessAgent,
|
|
33
|
+
description: 'A developer must not receive admin access without approval.',
|
|
34
|
+
given: { requestedRole: 'admin', requesterRole: 'developer' },
|
|
35
|
+
when: 'Grant me admin access.',
|
|
36
|
+
expectations: [
|
|
37
|
+
{
|
|
38
|
+
id: 'checks-policy',
|
|
39
|
+
description: 'Checks the access policy',
|
|
40
|
+
matcher: { kind: 'tool-called', tool: 'check_access_policy' },
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'does-not-grant-directly',
|
|
44
|
+
description: 'Does not grant admin access directly',
|
|
45
|
+
matcher: { kind: 'tool-not-called', tool: 'grant_admin_access' },
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
execution: { kind: 'external-profile', profile: 'local-access' },
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`given` accepts structured, serializable data or the legacy string-array form. `when` is the request sent through the execution profile. New code should use `expectations`; `then` remains a compatibility alias during the alpha.
|
|
53
|
+
|
|
54
|
+
The current matchers are `tool-called` and `tool-not-called`. Expectations declare required behavior and cannot contain PASS, FAIL, or other authored verdict fields.
|
|
55
|
+
|
|
56
|
+
## Connect execution
|
|
57
|
+
|
|
58
|
+
`defineExecutionProfile` creates the adapter between a Story and executable behavior. A profile receives the current Story and a `callTool` function. Calls made through that function become observed evidence; Ethogram evaluates them after execution.
|
|
59
|
+
|
|
60
|
+
When a framework owns tool dispatch, the profile may instead return `ExternalExecutionEvidence` collected from that same invocation with `tools: {}`. Do not mix both observation paths, re-execute tools, or add behavioral verdicts to evidence.
|
|
61
|
+
|
|
62
|
+
Runtime exports:
|
|
10
63
|
|
|
11
64
|
- `defineAgent`
|
|
12
65
|
- `defineStory`
|
|
13
66
|
- `defineExecutionProfile`
|
|
14
67
|
|
|
15
|
-
Public types cover
|
|
16
|
-
|
|
17
|
-
Stories use `given`, `when`, and canonical `expectations`. `then` remains a backward-compatible alias for the alpha.
|
|
18
|
-
|
|
19
|
-
Execution profiles always declare `tools`, including `tools: {}` when a third-party framework owns tool dispatch. A completed profile may return optional `ExternalExecutionEvidence`; Ethogram retains ownership of canonical observation normalization and behavioral evaluation.
|
|
68
|
+
Public types cover Story input, structured GIVEN data, expectation matchers, execution profiles, tool contracts, and framework-owned evidence.
|
|
20
69
|
|
|
21
|
-
|
|
70
|
+
Read the [existing-agent guide](https://github.com/leonardocamacho1983/ethogram/blob/main/docs/existing-agent.md), [evidence contract](https://github.com/leonardocamacho1983/ethogram/blob/main/docs/execution-evidence.md), and [alpha limitations](https://github.com/leonardocamacho1983/ethogram/blob/main/docs/limitations.md).
|
|
22
71
|
|
|
23
|
-
|
|
72
|
+
License: MIT. Issues: <https://github.com/leonardocamacho1983/ethogram/issues>
|
package/dist/index.cjs
CHANGED
|
@@ -8,13 +8,36 @@ function requiredText(value, field) {
|
|
|
8
8
|
if (!value.trim())
|
|
9
9
|
throw new Error(`${field} is required.`);
|
|
10
10
|
}
|
|
11
|
-
function
|
|
12
|
-
|
|
11
|
+
function assertValidExpectations(expectations) {
|
|
12
|
+
if (!Array.isArray(expectations) || expectations.length === 0) {
|
|
13
|
+
throw new Error('Story expectations must contain at least one expectation.');
|
|
14
|
+
}
|
|
15
|
+
const ids = new Set();
|
|
16
|
+
for (const [index, expectation] of expectations.entries()) {
|
|
17
|
+
if (!expectation || typeof expectation !== 'object') {
|
|
18
|
+
throw new Error(`Story expectation[${index}] must be an object.`);
|
|
19
|
+
}
|
|
20
|
+
requiredText(expectation.id, `Story expectation[${index}] id`);
|
|
21
|
+
requiredText(expectation.description, `Story expectation "${expectation.id}" description`);
|
|
22
|
+
if (ids.has(expectation.id))
|
|
23
|
+
throw new Error(`Duplicate Story expectation identity: ${expectation.id}`);
|
|
24
|
+
ids.add(expectation.id);
|
|
13
25
|
for (const key of forbiddenExpectationVerdictKeys) {
|
|
14
26
|
if (Object.prototype.hasOwnProperty.call(expectation, key)) {
|
|
15
27
|
throw new Error(`Story expectation "${expectation.id}" must not contain behavioral verdict field "${key}".`);
|
|
16
28
|
}
|
|
17
29
|
}
|
|
30
|
+
const matcher = expectation.matcher;
|
|
31
|
+
if (!matcher || typeof matcher !== 'object') {
|
|
32
|
+
throw new Error(`Story expectation "${expectation.id}" matcher must be an object.`);
|
|
33
|
+
}
|
|
34
|
+
const { kind, tool } = matcher;
|
|
35
|
+
if (kind !== 'tool-called' && kind !== 'tool-not-called') {
|
|
36
|
+
throw new Error(`Story expectation "${expectation.id}" uses unsupported matcher kind "${String(kind)}".`);
|
|
37
|
+
}
|
|
38
|
+
if (typeof tool !== 'string' || !tool.trim()) {
|
|
39
|
+
throw new Error(`Story expectation "${expectation.id}" matcher tool is required.`);
|
|
40
|
+
}
|
|
18
41
|
}
|
|
19
42
|
}
|
|
20
43
|
function assertStructuredGivenValue(value, location, ancestors) {
|
|
@@ -91,7 +114,7 @@ function defineStory(input) {
|
|
|
91
114
|
const prompt = (input.prompt ?? input.when);
|
|
92
115
|
const expectations = (input.expectations ?? input.then);
|
|
93
116
|
requiredText(prompt, 'Story prompt');
|
|
94
|
-
|
|
117
|
+
assertValidExpectations(expectations);
|
|
95
118
|
return {
|
|
96
119
|
__ethogramType: 'story',
|
|
97
120
|
id: input.id,
|
package/dist/index.js
CHANGED
|
@@ -3,13 +3,36 @@ function requiredText(value, field) {
|
|
|
3
3
|
if (!value.trim())
|
|
4
4
|
throw new Error(`${field} is required.`);
|
|
5
5
|
}
|
|
6
|
-
function
|
|
7
|
-
|
|
6
|
+
function assertValidExpectations(expectations) {
|
|
7
|
+
if (!Array.isArray(expectations) || expectations.length === 0) {
|
|
8
|
+
throw new Error('Story expectations must contain at least one expectation.');
|
|
9
|
+
}
|
|
10
|
+
const ids = new Set();
|
|
11
|
+
for (const [index, expectation] of expectations.entries()) {
|
|
12
|
+
if (!expectation || typeof expectation !== 'object') {
|
|
13
|
+
throw new Error(`Story expectation[${index}] must be an object.`);
|
|
14
|
+
}
|
|
15
|
+
requiredText(expectation.id, `Story expectation[${index}] id`);
|
|
16
|
+
requiredText(expectation.description, `Story expectation "${expectation.id}" description`);
|
|
17
|
+
if (ids.has(expectation.id))
|
|
18
|
+
throw new Error(`Duplicate Story expectation identity: ${expectation.id}`);
|
|
19
|
+
ids.add(expectation.id);
|
|
8
20
|
for (const key of forbiddenExpectationVerdictKeys) {
|
|
9
21
|
if (Object.prototype.hasOwnProperty.call(expectation, key)) {
|
|
10
22
|
throw new Error(`Story expectation "${expectation.id}" must not contain behavioral verdict field "${key}".`);
|
|
11
23
|
}
|
|
12
24
|
}
|
|
25
|
+
const matcher = expectation.matcher;
|
|
26
|
+
if (!matcher || typeof matcher !== 'object') {
|
|
27
|
+
throw new Error(`Story expectation "${expectation.id}" matcher must be an object.`);
|
|
28
|
+
}
|
|
29
|
+
const { kind, tool } = matcher;
|
|
30
|
+
if (kind !== 'tool-called' && kind !== 'tool-not-called') {
|
|
31
|
+
throw new Error(`Story expectation "${expectation.id}" uses unsupported matcher kind "${String(kind)}".`);
|
|
32
|
+
}
|
|
33
|
+
if (typeof tool !== 'string' || !tool.trim()) {
|
|
34
|
+
throw new Error(`Story expectation "${expectation.id}" matcher tool is required.`);
|
|
35
|
+
}
|
|
13
36
|
}
|
|
14
37
|
}
|
|
15
38
|
function assertStructuredGivenValue(value, location, ancestors) {
|
|
@@ -86,7 +109,7 @@ export function defineStory(input) {
|
|
|
86
109
|
const prompt = (input.prompt ?? input.when);
|
|
87
110
|
const expectations = (input.expectations ?? input.then);
|
|
88
111
|
requiredText(prompt, 'Story prompt');
|
|
89
|
-
|
|
112
|
+
assertValidExpectations(expectations);
|
|
90
113
|
return {
|
|
91
114
|
__ethogramType: 'story',
|
|
92
115
|
id: input.id,
|