@a-dray/aglib 0.1.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.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -0
  3. package/dist/agent.d.ts +158 -0
  4. package/dist/agent.js +2 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/content.d.ts +45 -0
  7. package/dist/content.js +11 -0
  8. package/dist/content.js.map +1 -0
  9. package/dist/harness/adapters/acp/index.d.ts +92 -0
  10. package/dist/harness/adapters/acp/index.js +479 -0
  11. package/dist/harness/adapters/acp/index.js.map +1 -0
  12. package/dist/harness/adapters/acp/rpc.d.ts +23 -0
  13. package/dist/harness/adapters/acp/rpc.js +103 -0
  14. package/dist/harness/adapters/acp/rpc.js.map +1 -0
  15. package/dist/harness/adapters/native/compaction.d.ts +16 -0
  16. package/dist/harness/adapters/native/compaction.js +55 -0
  17. package/dist/harness/adapters/native/compaction.js.map +1 -0
  18. package/dist/harness/adapters/native/index.d.ts +2 -0
  19. package/dist/harness/adapters/native/index.js +2 -0
  20. package/dist/harness/adapters/native/index.js.map +1 -0
  21. package/dist/harness/adapters/native/loop.d.ts +25 -0
  22. package/dist/harness/adapters/native/loop.js +153 -0
  23. package/dist/harness/adapters/native/loop.js.map +1 -0
  24. package/dist/harness/harness.d.ts +129 -0
  25. package/dist/harness/harness.js +2 -0
  26. package/dist/harness/harness.js.map +1 -0
  27. package/dist/harness/index.d.ts +3 -0
  28. package/dist/harness/index.js +2 -0
  29. package/dist/harness/index.js.map +1 -0
  30. package/dist/index.d.ts +10 -0
  31. package/dist/index.js +5 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/json.d.ts +4 -0
  34. package/dist/json.js +2 -0
  35. package/dist/json.js.map +1 -0
  36. package/dist/model/adapters/anthropic/index.d.ts +34 -0
  37. package/dist/model/adapters/anthropic/index.js +271 -0
  38. package/dist/model/adapters/anthropic/index.js.map +1 -0
  39. package/dist/model/adapters/fake/index.d.ts +27 -0
  40. package/dist/model/adapters/fake/index.js +37 -0
  41. package/dist/model/adapters/fake/index.js.map +1 -0
  42. package/dist/model/adapters/openai-compatible/index.d.ts +29 -0
  43. package/dist/model/adapters/openai-compatible/index.js +226 -0
  44. package/dist/model/adapters/openai-compatible/index.js.map +1 -0
  45. package/dist/model/conformance.d.ts +210 -0
  46. package/dist/model/conformance.js +427 -0
  47. package/dist/model/conformance.js.map +1 -0
  48. package/dist/model/index.d.ts +2 -0
  49. package/dist/model/index.js +2 -0
  50. package/dist/model/index.js.map +1 -0
  51. package/dist/model/model.d.ts +85 -0
  52. package/dist/model/model.js +8 -0
  53. package/dist/model/model.js.map +1 -0
  54. package/dist/result.d.ts +23 -0
  55. package/dist/result.js +3 -0
  56. package/dist/result.js.map +1 -0
  57. package/dist/run.d.ts +10 -0
  58. package/dist/run.js +477 -0
  59. package/dist/run.js.map +1 -0
  60. package/dist/sandbox/adapters/docker.d.ts +22 -0
  61. package/dist/sandbox/adapters/docker.js +443 -0
  62. package/dist/sandbox/adapters/docker.js.map +1 -0
  63. package/dist/sandbox/adapters/local.d.ts +11 -0
  64. package/dist/sandbox/adapters/local.js +284 -0
  65. package/dist/sandbox/adapters/local.js.map +1 -0
  66. package/dist/sandbox/conformance.d.ts +73 -0
  67. package/dist/sandbox/conformance.js +309 -0
  68. package/dist/sandbox/conformance.js.map +1 -0
  69. package/dist/sandbox/index.d.ts +1 -0
  70. package/dist/sandbox/index.js +2 -0
  71. package/dist/sandbox/index.js.map +1 -0
  72. package/dist/sandbox/sandbox.d.ts +172 -0
  73. package/dist/sandbox/sandbox.js +2 -0
  74. package/dist/sandbox/sandbox.js.map +1 -0
  75. package/dist/session/entry.d.ts +196 -0
  76. package/dist/session/entry.js +2 -0
  77. package/dist/session/entry.js.map +1 -0
  78. package/dist/session/index.d.ts +2 -0
  79. package/dist/session/index.js +2 -0
  80. package/dist/session/index.js.map +1 -0
  81. package/dist/session/log.d.ts +20 -0
  82. package/dist/session/log.js +24 -0
  83. package/dist/session/log.js.map +1 -0
  84. package/dist/session/messages.d.ts +42 -0
  85. package/dist/session/messages.js +99 -0
  86. package/dist/session/messages.js.map +1 -0
  87. package/dist/store/adapters/sqlite.d.ts +20 -0
  88. package/dist/store/adapters/sqlite.js +365 -0
  89. package/dist/store/adapters/sqlite.js.map +1 -0
  90. package/dist/store/conformance.d.ts +66 -0
  91. package/dist/store/conformance.js +580 -0
  92. package/dist/store/conformance.js.map +1 -0
  93. package/dist/store/index.d.ts +1 -0
  94. package/dist/store/index.js +2 -0
  95. package/dist/store/index.js.map +1 -0
  96. package/dist/store/store.d.ts +244 -0
  97. package/dist/store/store.js +2 -0
  98. package/dist/store/store.js.map +1 -0
  99. package/dist/tools/execute.d.ts +24 -0
  100. package/dist/tools/execute.js +105 -0
  101. package/dist/tools/execute.js.map +1 -0
  102. package/dist/tools/index.d.ts +2 -0
  103. package/dist/tools/index.js +2 -0
  104. package/dist/tools/index.js.map +1 -0
  105. package/dist/tools/tool.d.ts +106 -0
  106. package/dist/tools/tool.js +34 -0
  107. package/dist/tools/tool.js.map +1 -0
  108. package/package.json +119 -0
@@ -0,0 +1,106 @@
1
+ import type { Content } from "../content.js";
2
+ import type { Delivery, ToolCall, ToolResult } from "../session/entry.js";
3
+ import type { JsonValue } from "../json.js";
4
+ import { type Result } from "../result.js";
5
+ import { z } from "zod";
6
+ /** What a tool tells a model about itself. Declared here because a tool owns it. */
7
+ export interface ToolSpec {
8
+ name: string;
9
+ description: string;
10
+ /** JSON Schema. */
11
+ parameters: JsonValue;
12
+ annotations?: {
13
+ readOnly?: boolean;
14
+ sequential?: boolean;
15
+ };
16
+ }
17
+ export interface ToolContext {
18
+ sessionId: string;
19
+ runId: string;
20
+ callId: string;
21
+ signal: AbortSignal;
22
+ /**
23
+ * Deliver input to another session, committed with this run's own entries.
24
+ * This is the whole of agent-to-agent messaging: spawning a child, replying
25
+ * to a parent and messaging a peer are the same call, and either the sending
26
+ * turn commits with the delivery or neither happens.
27
+ */
28
+ enqueue(delivery: Delivery): void;
29
+ /** Progress for a live viewer. Never recovery state. */
30
+ report(data: JsonValue): void;
31
+ }
32
+ export interface Tool {
33
+ spec: ToolSpec;
34
+ /** Validates raw arguments once, before any authority decision sees them. */
35
+ prepare(raw: unknown): Result<{
36
+ input: JsonValue;
37
+ run(context: ToolContext): Promise<ToolResult>;
38
+ }, ToolResult>;
39
+ }
40
+ /**
41
+ * The entire permission model.
42
+ *
43
+ * One function over parsed arguments, supplied by the application, which
44
+ * already owns identity, tenancy and policy. There is no grant vocabulary, no
45
+ * principal and no second batch-level hook: anything those expressed, a closure
46
+ * expresses better.
47
+ *
48
+ * Two outcomes, not three. There was a `pause`, which parked the batch and
49
+ * committed an approval request — and nothing could ever resolve it, because
50
+ * resuming an exact batch is only possible in a harness we own, and three of
51
+ * the four are not. An approval that works in one harness and dead-ends in the
52
+ * others is worse than none. A call needing permission is rejected with a
53
+ * message saying so; the application asks whoever approves, and their answer
54
+ * arrives as ordinary input on the session, which is a path that already works
55
+ * everywhere. `recipes/agent-service` shows the whole round trip.
56
+ *
57
+ * The gate does not weaken by being a rejection: this runs on every call and
58
+ * cannot be routed around. What an application gives up is exact-argument
59
+ * replay, since the model re-issues rather than resuming. An application that
60
+ * needs the stronger thing keys its approval on the call id and a hash of the
61
+ * parsed input, so a re-issue that differs misses and is refused again.
62
+ */
63
+ export type Decide = (call: {
64
+ tool: ToolSpec;
65
+ input: JsonValue;
66
+ sessionId: string;
67
+ runId: string;
68
+ callId: string;
69
+ }) => {
70
+ action: "execute";
71
+ } | {
72
+ action: "reject";
73
+ message: string;
74
+ } | Promise<{
75
+ action: "execute";
76
+ } | {
77
+ action: "reject";
78
+ message: string;
79
+ }>;
80
+ /** What a harness is handed to reach application tools. */
81
+ export interface ToolExecutor {
82
+ list(): readonly ToolSpec[];
83
+ execute(input: {
84
+ calls: readonly ToolCall[];
85
+ signal?: AbortSignal;
86
+ }): Promise<{
87
+ results: readonly {
88
+ callId: string;
89
+ result: ToolResult;
90
+ }[];
91
+ }>;
92
+ }
93
+ /**
94
+ * Declares a tool from a runtime schema. The argument type of `execute` is
95
+ * derived from that schema, so there is never a hand-maintained interface to
96
+ * keep in step with the validation.
97
+ */
98
+ export declare function defineTool<TSchema extends z.ZodType>(input: {
99
+ name: string;
100
+ description: string;
101
+ schema: TSchema;
102
+ annotations?: ToolSpec["annotations"];
103
+ execute(args: z.output<TSchema>, context: ToolContext): ToolResult | Promise<ToolResult>;
104
+ }): Tool;
105
+ /** Re-exported for the same reason the model port re-exports its own. */
106
+ export type { Content, ToolResult };
@@ -0,0 +1,34 @@
1
+ import { err, ok } from "../result.js";
2
+ import { z } from "zod";
3
+ /**
4
+ * Declares a tool from a runtime schema. The argument type of `execute` is
5
+ * derived from that schema, so there is never a hand-maintained interface to
6
+ * keep in step with the validation.
7
+ */
8
+ export function defineTool(input) {
9
+ const parameters = z.toJSONSchema(input.schema);
10
+ return Object.freeze({
11
+ spec: Object.freeze({
12
+ name: input.name,
13
+ description: input.description,
14
+ parameters,
15
+ ...(input.annotations ? { annotations: input.annotations } : {}),
16
+ }),
17
+ prepare(raw) {
18
+ const parsed = input.schema.safeParse(raw);
19
+ if (!parsed.success) {
20
+ return err({
21
+ content: `Invalid arguments for ${input.name}: ${z.prettifyError(parsed.error)}`,
22
+ isError: true,
23
+ });
24
+ }
25
+ return ok({
26
+ input: parsed.data,
27
+ // Throws are normalized by the executor, which has to cover
28
+ // hand-written tools anyway; catching here too would be dead code.
29
+ run: async (context) => input.execute(parsed.data, context),
30
+ });
31
+ },
32
+ });
33
+ }
34
+ //# sourceMappingURL=tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/tools/tool.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA0ExB;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAA4B,KAMrD;IACC,MAAM,UAAU,GAAG,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAc,CAAC;IAC7D,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,UAAU;YACV,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC;QACF,OAAO,CAAC,GAAY;YAClB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,GAAG,CAAC;oBACT,OAAO,EAAE,yBAAyB,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;oBAChF,OAAO,EAAE,IAAI;iBACd,CAAC,CAAC;YACL,CAAC;YACD,OAAO,EAAE,CAAC;gBACR,KAAK,EAAE,MAAM,CAAC,IAAiB;gBAC/B,4DAA4D;gBAC5D,mEAAmE;gBACnE,GAAG,EAAE,KAAK,EAAE,OAAoB,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAyB,EAAE,OAAO,CAAC;aAC9F,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { Content } from \"../content.js\";\n\nimport type { Delivery, ToolCall, ToolResult } from \"../session/entry.js\";\nimport type { JsonValue } from \"../json.js\";\nimport { err, ok, type Result } from \"../result.js\";\nimport { z } from \"zod\";\n\n/** What a tool tells a model about itself. Declared here because a tool owns it. */\nexport interface ToolSpec {\n name: string;\n description: string;\n /** JSON Schema. */\n parameters: JsonValue;\n annotations?: { readOnly?: boolean; sequential?: boolean };\n}\n\nexport interface ToolContext {\n sessionId: string;\n runId: string;\n callId: string;\n signal: AbortSignal;\n /**\n * Deliver input to another session, committed with this run's own entries.\n * This is the whole of agent-to-agent messaging: spawning a child, replying\n * to a parent and messaging a peer are the same call, and either the sending\n * turn commits with the delivery or neither happens.\n */\n enqueue(delivery: Delivery): void;\n /** Progress for a live viewer. Never recovery state. */\n report(data: JsonValue): void;\n}\n\nexport interface Tool {\n spec: ToolSpec;\n /** Validates raw arguments once, before any authority decision sees them. */\n prepare(raw: unknown): Result<{ input: JsonValue; run(context: ToolContext): Promise<ToolResult> }, ToolResult>;\n}\n\n/**\n * The entire permission model.\n *\n * One function over parsed arguments, supplied by the application, which\n * already owns identity, tenancy and policy. There is no grant vocabulary, no\n * principal and no second batch-level hook: anything those expressed, a closure\n * expresses better.\n *\n * Two outcomes, not three. There was a `pause`, which parked the batch and\n * committed an approval request — and nothing could ever resolve it, because\n * resuming an exact batch is only possible in a harness we own, and three of\n * the four are not. An approval that works in one harness and dead-ends in the\n * others is worse than none. A call needing permission is rejected with a\n * message saying so; the application asks whoever approves, and their answer\n * arrives as ordinary input on the session, which is a path that already works\n * everywhere. `recipes/agent-service` shows the whole round trip.\n *\n * The gate does not weaken by being a rejection: this runs on every call and\n * cannot be routed around. What an application gives up is exact-argument\n * replay, since the model re-issues rather than resuming. An application that\n * needs the stronger thing keys its approval on the call id and a hash of the\n * parsed input, so a re-issue that differs misses and is refused again.\n */\nexport type Decide = (call: {\n tool: ToolSpec;\n input: JsonValue;\n sessionId: string;\n runId: string;\n callId: string;\n}) =>\n | { action: \"execute\" }\n | { action: \"reject\"; message: string }\n | Promise<{ action: \"execute\" } | { action: \"reject\"; message: string }>;\n\n/** What a harness is handed to reach application tools. */\nexport interface ToolExecutor {\n list(): readonly ToolSpec[];\n execute(input: { calls: readonly ToolCall[]; signal?: AbortSignal }):\n Promise<{ results: readonly { callId: string; result: ToolResult }[] }>;\n}\n\n/**\n * Declares a tool from a runtime schema. The argument type of `execute` is\n * derived from that schema, so there is never a hand-maintained interface to\n * keep in step with the validation.\n */\nexport function defineTool<TSchema extends z.ZodType>(input: {\n name: string;\n description: string;\n schema: TSchema;\n annotations?: ToolSpec[\"annotations\"];\n execute(args: z.output<TSchema>, context: ToolContext): ToolResult | Promise<ToolResult>;\n}): Tool {\n const parameters = z.toJSONSchema(input.schema) as JsonValue;\n return Object.freeze({\n spec: Object.freeze({\n name: input.name,\n description: input.description,\n parameters,\n ...(input.annotations ? { annotations: input.annotations } : {}),\n }),\n prepare(raw: unknown) {\n const parsed = input.schema.safeParse(raw);\n if (!parsed.success) {\n return err({\n content: `Invalid arguments for ${input.name}: ${z.prettifyError(parsed.error)}`,\n isError: true,\n });\n }\n return ok({\n input: parsed.data as JsonValue,\n // Throws are normalized by the executor, which has to cover\n // hand-written tools anyway; catching here too would be dead code.\n run: async (context: ToolContext) => input.execute(parsed.data as z.output<TSchema>, context),\n });\n },\n });\n}\n\n/** Re-exported for the same reason the model port re-exports its own. */\nexport type { Content, ToolResult };\n"]}
package/package.json ADDED
@@ -0,0 +1,119 @@
1
+ {
2
+ "name": "@a-dray/aglib",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "A small TypeScript toolkit for building your own agent harness.",
6
+ "license": "MIT",
7
+ "author": "Adam Dray",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/aj-dray/aglib.git"
11
+ },
12
+ "packageManager": "bun@1.3.14",
13
+ "engines": {
14
+ "node": ">=22.5.0"
15
+ },
16
+ "sideEffects": false,
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "LICENSE"
21
+ ],
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "import": "./dist/index.js"
29
+ },
30
+ "./session": {
31
+ "types": "./dist/session/index.d.ts",
32
+ "import": "./dist/session/index.js"
33
+ },
34
+ "./tools": {
35
+ "types": "./dist/tools/index.d.ts",
36
+ "import": "./dist/tools/index.js"
37
+ },
38
+ "./model": {
39
+ "types": "./dist/model/index.d.ts",
40
+ "import": "./dist/model/index.js"
41
+ },
42
+ "./model/conformance": {
43
+ "types": "./dist/model/conformance.d.ts",
44
+ "import": "./dist/model/conformance.js"
45
+ },
46
+ "./model/adapters/anthropic": {
47
+ "types": "./dist/model/adapters/anthropic/index.d.ts",
48
+ "import": "./dist/model/adapters/anthropic/index.js"
49
+ },
50
+ "./model/adapters/openai-compatible": {
51
+ "types": "./dist/model/adapters/openai-compatible/index.d.ts",
52
+ "import": "./dist/model/adapters/openai-compatible/index.js"
53
+ },
54
+ "./model/adapters/fake": {
55
+ "types": "./dist/model/adapters/fake/index.d.ts",
56
+ "import": "./dist/model/adapters/fake/index.js"
57
+ },
58
+ "./store": {
59
+ "types": "./dist/store/index.d.ts",
60
+ "import": "./dist/store/index.js"
61
+ },
62
+ "./store/conformance": {
63
+ "types": "./dist/store/conformance.d.ts",
64
+ "import": "./dist/store/conformance.js"
65
+ },
66
+ "./store/adapters/sqlite": {
67
+ "types": "./dist/store/adapters/sqlite.d.ts",
68
+ "import": "./dist/store/adapters/sqlite.js"
69
+ },
70
+ "./harness": {
71
+ "types": "./dist/harness/index.d.ts",
72
+ "import": "./dist/harness/index.js"
73
+ },
74
+ "./harness/adapters/acp": {
75
+ "types": "./dist/harness/adapters/acp/index.d.ts",
76
+ "import": "./dist/harness/adapters/acp/index.js"
77
+ },
78
+ "./sandbox": {
79
+ "types": "./dist/sandbox/index.d.ts",
80
+ "import": "./dist/sandbox/index.js"
81
+ },
82
+ "./sandbox/conformance": {
83
+ "types": "./dist/sandbox/conformance.d.ts",
84
+ "import": "./dist/sandbox/conformance.js"
85
+ },
86
+ "./sandbox/adapters/local": {
87
+ "types": "./dist/sandbox/adapters/local.d.ts",
88
+ "import": "./dist/sandbox/adapters/local.js"
89
+ },
90
+ "./sandbox/adapters/docker": {
91
+ "types": "./dist/sandbox/adapters/docker.d.ts",
92
+ "import": "./dist/sandbox/adapters/docker.js"
93
+ }
94
+ },
95
+ "dependencies": {
96
+ "zod": "^4.4.3"
97
+ },
98
+ "devDependencies": {
99
+ "@types/bun": "^1.3.14",
100
+ "typescript": "^6.0.3"
101
+ },
102
+ "workspaces": [
103
+ "recipes/*"
104
+ ],
105
+ "scripts": {
106
+ "build": "bun scripts/build.ts",
107
+ "prepare": "bun run build",
108
+ "check": "bun run typecheck && bun test src scripts && bun run build && bun run node:verify && bun run recipes:verify && bun run docs:check && bun scripts/checks.ts",
109
+ "typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.scripts.json",
110
+ "test": "bun run build && bun test src scripts recipes",
111
+ "checks": "bun run build && bun scripts/checks.ts",
112
+ "recipes:verify": "tsc -p tsconfig.recipes.json && bun test recipes",
113
+ "recipe": "bun run build && bun scripts/recipe.ts",
114
+ "docs": "bun scripts/docs.ts",
115
+ "docs:check": "bun scripts/docs.ts --check",
116
+ "node:verify": "node scripts/node-verify.mjs",
117
+ "prepack": "bun run build"
118
+ }
119
+ }