@intx/agent 0.2.2 → 0.3.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 +2 -2
- package/dist/agent.d.ts +30 -1
- package/dist/agent.js +45 -1
- package/dist/definition.d.ts +23 -0
- package/dist/definition.js +1 -0
- package/dist/director-registry.d.ts +9 -0
- package/dist/director-registry.js +14 -0
- package/dist/director.d.ts +14 -0
- package/dist/director.js +39 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/internal-fixtures/mail.js +1 -0
- package/dist/tool.d.ts +58 -2
- package/dist/tool.js +30 -1
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -16,13 +16,13 @@ import {
|
|
|
16
16
|
defineAgent,
|
|
17
17
|
} from "@intx/agent";
|
|
18
18
|
import { noopAuditStore, permissiveAuthorize } from "@intx/agent/testing";
|
|
19
|
-
import { createIsogitStore } from "@intx/storage-isogit";
|
|
19
|
+
import { createIsogitStore } from "@intx/storage-isogit/node";
|
|
20
20
|
|
|
21
21
|
// `apiKey` and `model` come from the caller's env / config; pick the
|
|
22
22
|
// shape that fits the deployment. The snippet below uses literals so
|
|
23
23
|
// it copy-pastes cleanly.
|
|
24
24
|
const apiKey = process.env.ANTHROPIC_API_KEY ?? "";
|
|
25
|
-
const model = "claude-sonnet-
|
|
25
|
+
const model = "claude-sonnet-5";
|
|
26
26
|
const source = {
|
|
27
27
|
id: `anthropic:${model}`,
|
|
28
28
|
provider: "anthropic",
|
package/dist/agent.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ReactorEmittedEvent } from "@intx/inference";
|
|
2
|
-
import type { BlobReader, ContextCommit, ConversationTurn, InboundMessage, InferenceSource } from "@intx/types/runtime";
|
|
2
|
+
import type { ApprovalSnapshot, BlobReader, ContextCommit, ConversationTurn, InboundMessage, InferenceSource } from "@intx/types/runtime";
|
|
3
3
|
import type { AgentDefinition } from "./definition.js";
|
|
4
4
|
import type { BaseEnv } from "./env.js";
|
|
5
5
|
export type SendOptions = {
|
|
@@ -17,6 +17,7 @@ export type SendOptions = {
|
|
|
17
17
|
from?: string;
|
|
18
18
|
};
|
|
19
19
|
export type SendResult = {
|
|
20
|
+
type: "reply";
|
|
20
21
|
/** Reply text emitted by the director's `reply` action. */
|
|
21
22
|
reply: string;
|
|
22
23
|
/**
|
|
@@ -24,7 +25,35 @@ export type SendResult = {
|
|
|
24
25
|
* the reactor's `inference.done` event preceding `connector.reply`.
|
|
25
26
|
*/
|
|
26
27
|
turn: ConversationTurn;
|
|
28
|
+
} | {
|
|
29
|
+
/**
|
|
30
|
+
* The reactor parked on a gate before producing a reply. The cycle
|
|
31
|
+
* is not finished -- it will resume when the correlated external
|
|
32
|
+
* decision is delivered. `correlationId` identifies the pending
|
|
33
|
+
* operation the caller resumes against.
|
|
34
|
+
*/
|
|
35
|
+
type: "suspended";
|
|
36
|
+
correlationId: string;
|
|
37
|
+
/**
|
|
38
|
+
* Approver-facing snapshot of the parked tool call, when the reactor
|
|
39
|
+
* carried one on the gate-blocked event. Forwarded so the runtime can
|
|
40
|
+
* register it with the suspension. Absent for suspensions with no
|
|
41
|
+
* snapshot (an authz extension wired with no tool definitions).
|
|
42
|
+
*/
|
|
43
|
+
approvalSnapshot?: ApprovalSnapshot;
|
|
27
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* A `reactor.gate.blocked` event settled the active send but carried no
|
|
47
|
+
* `correlationId`, so the resulting suspension has no handle a caller
|
|
48
|
+
* could resume against. The reactor omits `correlationId` for gates
|
|
49
|
+
* parked without a correlation (e.g. a director suspend with no
|
|
50
|
+
* correlated external decision), and `send()` cannot hand back an
|
|
51
|
+
* unresumable outcome -- it surfaces this instead.
|
|
52
|
+
*/
|
|
53
|
+
export declare class GateSuspendedWithoutCorrelationError extends Error {
|
|
54
|
+
readonly gateId: string;
|
|
55
|
+
constructor(gateId: string);
|
|
56
|
+
}
|
|
28
57
|
export type Agent = {
|
|
29
58
|
send(content: string | InboundMessage, opts?: SendOptions): Promise<SendResult>;
|
|
30
59
|
stream(): AsyncIterable<ReactorEmittedEvent>;
|
package/dist/agent.js
CHANGED
|
@@ -71,6 +71,22 @@ const DEFAULT_SEND_TO = "agent@local";
|
|
|
71
71
|
const DEFAULT_SEND_QUEUE_MAX = 16;
|
|
72
72
|
const DEFAULT_STREAM_BUFFER_MAX = 1024;
|
|
73
73
|
const DEFAULT_CLOSE_TIMEOUT_MS = 5000;
|
|
74
|
+
/**
|
|
75
|
+
* A `reactor.gate.blocked` event settled the active send but carried no
|
|
76
|
+
* `correlationId`, so the resulting suspension has no handle a caller
|
|
77
|
+
* could resume against. The reactor omits `correlationId` for gates
|
|
78
|
+
* parked without a correlation (e.g. a director suspend with no
|
|
79
|
+
* correlated external decision), and `send()` cannot hand back an
|
|
80
|
+
* unresumable outcome -- it surfaces this instead.
|
|
81
|
+
*/
|
|
82
|
+
export class GateSuspendedWithoutCorrelationError extends Error {
|
|
83
|
+
gateId;
|
|
84
|
+
constructor(gateId) {
|
|
85
|
+
super(`reactor suspended on gate ${gateId} without a correlationId; the send has no handle to resume against`);
|
|
86
|
+
this.name = "GateSuspendedWithoutCorrelationError";
|
|
87
|
+
this.gateId = gateId;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
74
90
|
export class AgentClosedError extends Error {
|
|
75
91
|
constructor() {
|
|
76
92
|
super("agent is closed");
|
|
@@ -391,7 +407,34 @@ export async function createAgent(def, env) {
|
|
|
391
407
|
const turn = activeCycle.lastAssistantTurn ??
|
|
392
408
|
buildSyntheticTurn(event.data.content);
|
|
393
409
|
activeCycle = null;
|
|
394
|
-
sendQueue.resolveActive({
|
|
410
|
+
sendQueue.resolveActive({
|
|
411
|
+
type: "reply",
|
|
412
|
+
reply: event.data.content,
|
|
413
|
+
turn,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
else if (event.type === "reactor.gate.blocked") {
|
|
417
|
+
// The reactor parked on a gate before producing a reply. This
|
|
418
|
+
// is a terminal outcome for the active send: the cycle will not
|
|
419
|
+
// continue until the correlated external decision is delivered,
|
|
420
|
+
// and a parked cycle does not emit connector.reply or
|
|
421
|
+
// reactor.done, so leaving the send unsettled would hang the
|
|
422
|
+
// caller. Resolve with the suspended outcome so the caller can
|
|
423
|
+
// resume against the correlationId. A gate parked without a
|
|
424
|
+
// correlationId is unresumable -- surface it rather than hand
|
|
425
|
+
// back an outcome with no handle.
|
|
426
|
+
const { correlationId, approvalSnapshot } = event.data;
|
|
427
|
+
activeCycle = null;
|
|
428
|
+
if (correlationId === undefined) {
|
|
429
|
+
sendQueue.rejectActive(new GateSuspendedWithoutCorrelationError(event.data.gateId));
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
sendQueue.resolveActive({
|
|
433
|
+
type: "suspended",
|
|
434
|
+
correlationId,
|
|
435
|
+
...(approvalSnapshot !== undefined ? { approvalSnapshot } : {}),
|
|
436
|
+
});
|
|
437
|
+
}
|
|
395
438
|
}
|
|
396
439
|
else if (event.type === "reactor.error" && event.data.fatal) {
|
|
397
440
|
// Only fatal reactor errors terminate the active send. Non-fatal
|
|
@@ -451,6 +494,7 @@ export async function createAgent(def, env) {
|
|
|
451
494
|
onEvent: handleEvent,
|
|
452
495
|
auditStore,
|
|
453
496
|
authorize,
|
|
497
|
+
toolDefinitions: resolvedTools.definitions,
|
|
454
498
|
onShutdown: async () => {
|
|
455
499
|
try {
|
|
456
500
|
await flushErrors();
|
package/dist/definition.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ToolPackagePin } from "@intx/types/tool-packages";
|
|
1
2
|
import type { AnnotatedToolFactory } from "./tool.js";
|
|
2
3
|
import type { BaseEnv } from "./env.js";
|
|
3
4
|
import type { DirectorRef } from "./director-types.js";
|
|
@@ -37,6 +38,19 @@ export interface AgentDefinition<EnvReq extends BaseEnv = BaseEnv> {
|
|
|
37
38
|
readonly systemPrompt: string;
|
|
38
39
|
readonly director?: DirectorRef;
|
|
39
40
|
readonly toolFactories: readonly AnnotatedToolFactory<EnvReq>[];
|
|
41
|
+
/**
|
|
42
|
+
* Tool-package names whose `definePlugin` factories this agent uses
|
|
43
|
+
* (`["@intx/tools-lsp"]`). Unlike a tool factory -- which the agent
|
|
44
|
+
* imports and places in `toolFactories`, so it is agent-visible -- a
|
|
45
|
+
* plugin package contributes NO agent-visible factory: its plugin
|
|
46
|
+
* factory reaches the agent only through `env.plugins`, wired by the
|
|
47
|
+
* host. This explicit per-agent list is therefore the only way per-step
|
|
48
|
+
* plugin scoping and the plugin's contributed tool grants can be known
|
|
49
|
+
* from the definition alone. The field is part of the hashed wire
|
|
50
|
+
* surface (the live->inert projector carries it), so a tampered plugin
|
|
51
|
+
* set fails re-verify. Absent when the agent uses no plugins.
|
|
52
|
+
*/
|
|
53
|
+
readonly plugins?: readonly string[];
|
|
40
54
|
readonly capabilities: readonly string[];
|
|
41
55
|
readonly inference: {
|
|
42
56
|
readonly sources: readonly InferencePreference[];
|
|
@@ -56,6 +70,13 @@ export interface AgentDefinition<EnvReq extends BaseEnv = BaseEnv> {
|
|
|
56
70
|
* encoded JSON in a tag value.
|
|
57
71
|
*/
|
|
58
72
|
readonly tags?: Readonly<Record<string, string>>;
|
|
73
|
+
/**
|
|
74
|
+
* Tool-package pins the sidecar materializes for this agent, carried on the
|
|
75
|
+
* definition so a folded workflow asset is self-contained rather than
|
|
76
|
+
* depending on pins supplied only at deploy time. Plain-data mirror of the
|
|
77
|
+
* pins the deploy-tree tool channel consumes.
|
|
78
|
+
*/
|
|
79
|
+
readonly toolPackagePins?: readonly ToolPackagePin[];
|
|
59
80
|
}
|
|
60
81
|
type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
61
82
|
type EnvRequiredBy<F> = F extends AnnotatedToolFactory<infer E> ? E : never;
|
|
@@ -101,6 +122,8 @@ export interface DefineAgentConfig<Factories extends readonly AnnotatedToolFacto
|
|
|
101
122
|
readonly systemPrompt: string;
|
|
102
123
|
readonly director?: DirectorRef;
|
|
103
124
|
readonly tools: Factories;
|
|
125
|
+
/** Plugin-package names this agent uses; see `AgentDefinition.plugins`. */
|
|
126
|
+
readonly plugins?: readonly string[];
|
|
104
127
|
readonly capabilities: readonly string[];
|
|
105
128
|
readonly inference: {
|
|
106
129
|
readonly sources: readonly InferencePreference[];
|
package/dist/definition.js
CHANGED
|
@@ -29,6 +29,7 @@ export function defineAgent(config) {
|
|
|
29
29
|
toolFactories,
|
|
30
30
|
capabilities: config.capabilities,
|
|
31
31
|
inference: config.inference,
|
|
32
|
+
...(config.plugins !== undefined ? { plugins: config.plugins } : {}),
|
|
32
33
|
...(config.description !== undefined
|
|
33
34
|
? { description: config.description }
|
|
34
35
|
: {}),
|
|
@@ -35,4 +35,13 @@ export declare function createDirectorRegistry(opts: {
|
|
|
35
35
|
* factories pass them into `createDirectorRegistry` directly.
|
|
36
36
|
*/
|
|
37
37
|
export declare function createDefaultDirectorRegistry(): DirectorRegistry;
|
|
38
|
+
/**
|
|
39
|
+
* Build the director registry for a workflow closure: the built-in default
|
|
40
|
+
* plus the closure's own `defineDirector` factories. A closure that ships no
|
|
41
|
+
* directors passes `loaded: []` and composes to `[defaultDirectorFactory]` --
|
|
42
|
+
* identical to `createDefaultDirectorRegistry`. A closure director whose id
|
|
43
|
+
* shadows the built-in (or another loaded director) throws at construction,
|
|
44
|
+
* the same fail-loud `createDirectorRegistry` applies to any duplicate.
|
|
45
|
+
*/
|
|
46
|
+
export declare function createWorkflowDirectorRegistry(loaded: readonly AnnotatedDirectorFactory<unknown, BaseEnv>[]): DirectorRegistry;
|
|
38
47
|
export {};
|
|
@@ -71,3 +71,17 @@ export function createDefaultDirectorRegistry() {
|
|
|
71
71
|
defaultId: defaultDirectorFactory.id,
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Build the director registry for a workflow closure: the built-in default
|
|
76
|
+
* plus the closure's own `defineDirector` factories. A closure that ships no
|
|
77
|
+
* directors passes `loaded: []` and composes to `[defaultDirectorFactory]` --
|
|
78
|
+
* identical to `createDefaultDirectorRegistry`. A closure director whose id
|
|
79
|
+
* shadows the built-in (or another loaded director) throws at construction,
|
|
80
|
+
* the same fail-loud `createDirectorRegistry` applies to any duplicate.
|
|
81
|
+
*/
|
|
82
|
+
export function createWorkflowDirectorRegistry(loaded) {
|
|
83
|
+
return createDirectorRegistry({
|
|
84
|
+
factories: [defaultDirectorFactory, ...loaded],
|
|
85
|
+
defaultId: defaultDirectorFactory.id,
|
|
86
|
+
});
|
|
87
|
+
}
|
package/dist/director.d.ts
CHANGED
|
@@ -54,3 +54,17 @@ export declare function defineDirector<Config, EnvReq extends BaseEnv = BaseEnv>
|
|
|
54
54
|
* malformed config to the factory.
|
|
55
55
|
*/
|
|
56
56
|
export declare function validateDirectorConfig(config: unknown, schema: DirectorConfigSchema): void;
|
|
57
|
+
/**
|
|
58
|
+
* Structural check for an `AnnotatedDirectorFactory` export. The shape is
|
|
59
|
+
* callable + `{ id: string, requires: string[], configSchema: function }`.
|
|
60
|
+
* The `configSchema` field is the discriminator against tool factories
|
|
61
|
+
* (which carry only `id` and `requires`); without it, any tool-factory
|
|
62
|
+
* export from a directors-entry module would be accepted as a director.
|
|
63
|
+
*
|
|
64
|
+
* Shared by the tool-package loader (`@intx/tool-packaging`) and the
|
|
65
|
+
* workflow-closure director loader (`@intx/workflow-host`) so both accept
|
|
66
|
+
* and reject exactly the same shapes -- one accept/reject rule the
|
|
67
|
+
* approval-time probe and the runtime cannot drift apart on. Two copies of
|
|
68
|
+
* "is this a valid director" would be a silent congruence hole.
|
|
69
|
+
*/
|
|
70
|
+
export declare function isAnnotatedDirectorFactory(value: unknown): value is AnnotatedDirectorFactory<unknown, BaseEnv>;
|
package/dist/director.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
// factories it wants rather than relying on import-order.
|
|
16
16
|
import { type } from "arktype";
|
|
17
17
|
import { validateNamespacedId } from "./namespace.js";
|
|
18
|
+
import { isAnnotatedPluginFactory } from "./tool.js";
|
|
18
19
|
/**
|
|
19
20
|
* Define a director factory.
|
|
20
21
|
*
|
|
@@ -90,3 +91,41 @@ function validateConfig(config, schema) {
|
|
|
90
91
|
export function validateDirectorConfig(config, schema) {
|
|
91
92
|
validateConfig(config, schema);
|
|
92
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Structural check for an `AnnotatedDirectorFactory` export. The shape is
|
|
96
|
+
* callable + `{ id: string, requires: string[], configSchema: function }`.
|
|
97
|
+
* The `configSchema` field is the discriminator against tool factories
|
|
98
|
+
* (which carry only `id` and `requires`); without it, any tool-factory
|
|
99
|
+
* export from a directors-entry module would be accepted as a director.
|
|
100
|
+
*
|
|
101
|
+
* Shared by the tool-package loader (`@intx/tool-packaging`) and the
|
|
102
|
+
* workflow-closure director loader (`@intx/workflow-host`) so both accept
|
|
103
|
+
* and reject exactly the same shapes -- one accept/reject rule the
|
|
104
|
+
* approval-time probe and the runtime cannot drift apart on. Two copies of
|
|
105
|
+
* "is this a valid director" would be a silent congruence hole.
|
|
106
|
+
*/
|
|
107
|
+
export function isAnnotatedDirectorFactory(value) {
|
|
108
|
+
if (typeof value !== "function")
|
|
109
|
+
return false;
|
|
110
|
+
if (isAnnotatedPluginFactory(value))
|
|
111
|
+
return false;
|
|
112
|
+
if (!("id" in value) || !("requires" in value))
|
|
113
|
+
return false;
|
|
114
|
+
if (!("configSchema" in value))
|
|
115
|
+
return false;
|
|
116
|
+
const id = value.id;
|
|
117
|
+
const requires = value.requires;
|
|
118
|
+
const configSchema = value.configSchema;
|
|
119
|
+
if (typeof id !== "string")
|
|
120
|
+
return false;
|
|
121
|
+
if (!Array.isArray(requires))
|
|
122
|
+
return false;
|
|
123
|
+
if (!requires.every((r) => typeof r === "string"))
|
|
124
|
+
return false;
|
|
125
|
+
// `defineDirector` requires a callable arktype validator. A non-callable
|
|
126
|
+
// schema would crash later inside config validation; reject here so the
|
|
127
|
+
// failure surfaces at load time rather than at first config-validation.
|
|
128
|
+
if (typeof configSchema !== "function")
|
|
129
|
+
return false;
|
|
130
|
+
return true;
|
|
131
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export { AgentContextLockError } from "./lock.js";
|
|
2
|
-
export { type AgentTool, type AgentToolRunner, type AnnotatedPluginFactory, type AnnotatedPluginMeta, type AnnotatedToolFactory, type PluginFactory, type StringToolHandler, type ToolBundle, type ToolFactory, type ToolFactoryMeta, type ToolHandler, DuplicateToolError, PLUGIN_MARKER, TOOL_PLUGIN_KIND, type ToolPluginKind, createToolRunner, defineTool, definePlugin, fromToolRunner, isAnnotatedPluginFactory, isToolPluginInstance, stringTool, tool, } from "./tool.js";
|
|
2
|
+
export { type AgentTool, type AgentToolRunner, type AnnotatedPluginFactory, type AnnotatedPluginMeta, type AnnotatedToolFactory, type PluginFactory, type StringToolHandler, type ToolBundle, type ToolDeclaration, type ToolFactory, type ToolFactoryMeta, type ToolHandler, DuplicateToolError, PLUGIN_MARKER, TOOL_PLUGIN_KIND, type ToolPluginKind, createToolRunner, defineTool, definePlugin, fromToolRunner, isAnnotatedPluginFactory, isToolPluginInstance, stringTool, tool, toolApprovalEffect, } from "./tool.js";
|
|
3
3
|
export { type AuthorizeFn, type BaseEnv, type Dependencies, AgentEnvError, } from "./env.js";
|
|
4
4
|
export { type AnnotatedDirectorFactory, type DirectorAgentContext, type DirectorConfigSchema, type DirectorFactory, type DirectorFactoryMeta, type DirectorRef, type DirectorRegistry, } from "./director-types.js";
|
|
5
5
|
export { validateNamespacedId } from "./namespace.js";
|
|
6
6
|
export { CanonicalizationError, canonicalizeForHash } from "./canonicalize.js";
|
|
7
|
-
export { type DefinedDirector, defineDirector } from "./director.js";
|
|
8
|
-
export { createDefaultDirectorRegistry, createDirectorRegistry, UnknownDirectorIdError, } from "./director-registry.js";
|
|
7
|
+
export { type DefinedDirector, defineDirector, isAnnotatedDirectorFactory, } from "./director.js";
|
|
8
|
+
export { createDefaultDirectorRegistry, createDirectorRegistry, createWorkflowDirectorRegistry, UnknownDirectorIdError, } from "./director-registry.js";
|
|
9
9
|
export { type DefaultDirectorConfig, buildDefaultDirectorRef, defaultDirectorFactory, } from "./default-director.js";
|
|
10
10
|
export { type SourceRegistry, InvalidInferenceSourceError, SourceNotFoundError, createSourceRegistry, } from "./source.js";
|
|
11
|
-
export { type Agent, type SendOptions, type SendResult, AgentClosedError, createAgent, } from "./agent.js";
|
|
11
|
+
export { type Agent, type SendOptions, type SendResult, AgentClosedError, GateSuspendedWithoutCorrelationError, createAgent, } from "./agent.js";
|
|
12
12
|
export { type AgentDefinition, type DefineAgentConfig, type EnvRequiredByAll, type InferencePreference, defineAgent, } from "./definition.js";
|
|
13
13
|
export { effectiveDirectorRef, getRequiredEnvKeys, validateEnv, } from "./env-validation.js";
|
|
14
14
|
export type { RequiredEnvKeys } from "./env-validation.js";
|
package/dist/index.js
CHANGED
|
@@ -7,16 +7,16 @@
|
|
|
7
7
|
// connector threads, outbound replies via MessageTransport) while the
|
|
8
8
|
// agent drives it from in-process calls.
|
|
9
9
|
export { AgentContextLockError } from "./lock.js";
|
|
10
|
-
export { DuplicateToolError, PLUGIN_MARKER, TOOL_PLUGIN_KIND, createToolRunner, defineTool, definePlugin, fromToolRunner, isAnnotatedPluginFactory, isToolPluginInstance, stringTool, tool, } from "./tool.js";
|
|
10
|
+
export { DuplicateToolError, PLUGIN_MARKER, TOOL_PLUGIN_KIND, createToolRunner, defineTool, definePlugin, fromToolRunner, isAnnotatedPluginFactory, isToolPluginInstance, stringTool, tool, toolApprovalEffect, } from "./tool.js";
|
|
11
11
|
export { AgentEnvError, } from "./env.js";
|
|
12
12
|
export {} from "./director-types.js";
|
|
13
13
|
export { validateNamespacedId } from "./namespace.js";
|
|
14
14
|
export { CanonicalizationError, canonicalizeForHash } from "./canonicalize.js";
|
|
15
|
-
export { defineDirector } from "./director.js";
|
|
16
|
-
export { createDefaultDirectorRegistry, createDirectorRegistry, UnknownDirectorIdError, } from "./director-registry.js";
|
|
15
|
+
export { defineDirector, isAnnotatedDirectorFactory, } from "./director.js";
|
|
16
|
+
export { createDefaultDirectorRegistry, createDirectorRegistry, createWorkflowDirectorRegistry, UnknownDirectorIdError, } from "./director-registry.js";
|
|
17
17
|
export { buildDefaultDirectorRef, defaultDirectorFactory, } from "./default-director.js";
|
|
18
18
|
export { InvalidInferenceSourceError, SourceNotFoundError, createSourceRegistry, } from "./source.js";
|
|
19
|
-
export { AgentClosedError, createAgent, } from "./agent.js";
|
|
19
|
+
export { AgentClosedError, GateSuspendedWithoutCorrelationError, createAgent, } from "./agent.js";
|
|
20
20
|
export { defineAgent, } from "./definition.js";
|
|
21
21
|
export { effectiveDirectorRef, getRequiredEnvKeys, validateEnv, } from "./env-validation.js";
|
|
22
22
|
export { SendQueueFullError } from "./send-queue.js";
|
package/dist/tool.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { GrantEffect } from "@intx/types";
|
|
1
2
|
import type { ToolCall, ToolDefinition, ToolResult, ToolRunner } from "@intx/types/runtime";
|
|
2
3
|
import type { BaseEnv } from "./env.js";
|
|
3
4
|
export type ToolHandler = (call: ToolCall, signal: AbortSignal) => Promise<ToolResult>;
|
|
@@ -60,14 +61,44 @@ export interface ToolBundle {
|
|
|
60
61
|
* instantiation.
|
|
61
62
|
*/
|
|
62
63
|
export type ToolFactory<EnvReq extends BaseEnv = BaseEnv> = (env: EnvReq) => ToolBundle;
|
|
64
|
+
/**
|
|
65
|
+
* Static, per-definition declaration a tool factory carries so callers
|
|
66
|
+
* (e.g. the deploy-time capability walk) can enumerate the tool names a
|
|
67
|
+
* factory contributes WITHOUT instantiating it. `approval` marks a tool
|
|
68
|
+
* as requiring per-invocation approval; it is a deliberate subset of
|
|
69
|
+
* GrantEffect (only "ask" is expressible here — a declaration can request
|
|
70
|
+
* a gate, never a pre-deny).
|
|
71
|
+
*/
|
|
72
|
+
export interface ToolDeclaration {
|
|
73
|
+
readonly name: string;
|
|
74
|
+
readonly approval?: "ask";
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Map a tool's static approval mark to the `GrantEffect` floor its
|
|
78
|
+
* `tool:<name>` grant carries: an `ask`-marked tool floors at `ask` (its
|
|
79
|
+
* invocation must clear an approval gate), every other tool floors at
|
|
80
|
+
* `allow`.
|
|
81
|
+
*
|
|
82
|
+
* This is the single canonical derivation of a tool's authorization floor
|
|
83
|
+
* from its declaration. Both the deploy-time capability walk (hub-side)
|
|
84
|
+
* and the per-step tool authorization (sidecar-side) route through here so
|
|
85
|
+
* a pinned tool loaded in the child derives the SAME floor the walk would
|
|
86
|
+
* have derived from an inline declaration. A divergence between the two
|
|
87
|
+
* sites would let a pinned `ask` tool authorize as `allow` (or vice
|
|
88
|
+
* versa), so the mapping lives in exactly one place.
|
|
89
|
+
*/
|
|
90
|
+
export declare function toolApprovalEffect(declaration: Pick<ToolDeclaration, "approval">): GrantEffect;
|
|
63
91
|
/**
|
|
64
92
|
* Runtime metadata attached to a `ToolFactory` by `defineTool`. `id` is
|
|
65
93
|
* package-namespaced; `requires` enumerates env keys the factory touches
|
|
66
|
-
* beyond `BaseEnv`'s six core fields
|
|
94
|
+
* beyond `BaseEnv`'s six core fields; `definitions` statically declares
|
|
95
|
+
* the tool names the factory contributes so callers can enumerate them
|
|
96
|
+
* without instantiating the factory.
|
|
67
97
|
*/
|
|
68
98
|
export interface ToolFactoryMeta {
|
|
69
99
|
readonly id: string;
|
|
70
100
|
readonly requires: readonly string[];
|
|
101
|
+
readonly definitions: readonly ToolDeclaration[];
|
|
71
102
|
}
|
|
72
103
|
/**
|
|
73
104
|
* A tool factory carrying its runtime metadata. `defineTool` is the only
|
|
@@ -87,15 +118,20 @@ export type AnnotatedToolFactory<EnvReq extends BaseEnv = BaseEnv> = ToolFactory
|
|
|
87
118
|
* `BaseEnv`'s six core fields. The runtime `validateEnv` checks
|
|
88
119
|
* presence; the factory itself may also fail loud at construction
|
|
89
120
|
* if the env contents are structurally wrong.
|
|
121
|
+
* - `definitions` statically declares the tool names this factory
|
|
122
|
+
* contributes so callers (e.g. the deploy-time capability walk) can
|
|
123
|
+
* enumerate them without instantiating the factory.
|
|
90
124
|
* - `factory(env)` returns a `ToolBundle`. Invoked once per agent
|
|
91
125
|
* instantiation; the bundle's lifetime is tied to that agent.
|
|
92
126
|
*
|
|
93
127
|
* The returned object is the same callable as the supplied `factory`
|
|
94
|
-
* with `id
|
|
128
|
+
* with `id`, a frozen `requires` array, and a frozen `definitions`
|
|
129
|
+
* array attached.
|
|
95
130
|
*/
|
|
96
131
|
export declare function defineTool<EnvReq extends BaseEnv = BaseEnv>(opts: {
|
|
97
132
|
id: string;
|
|
98
133
|
requires?: readonly string[];
|
|
134
|
+
definitions: readonly ToolDeclaration[];
|
|
99
135
|
factory: ToolFactory<EnvReq>;
|
|
100
136
|
}): AnnotatedToolFactory<EnvReq>;
|
|
101
137
|
/**
|
|
@@ -126,6 +162,20 @@ export declare const PLUGIN_MARKER: unique symbol;
|
|
|
126
162
|
export interface AnnotatedPluginMeta {
|
|
127
163
|
readonly id: string;
|
|
128
164
|
readonly requires: readonly string[];
|
|
165
|
+
/**
|
|
166
|
+
* Static declaration of the tool names this plugin contributes at
|
|
167
|
+
* runtime, so a caller can enumerate the plugin's tool grant surface
|
|
168
|
+
* WITHOUT instantiating it (which for a plugin like LSP would start a
|
|
169
|
+
* language-server subprocess). A plugin adds its tools indirectly -- it
|
|
170
|
+
* hands a host-defined shape to the tool package that consumes
|
|
171
|
+
* `env.plugins`, which then registers the plugin's tools under its own
|
|
172
|
+
* bundle -- so the plugin's contributed tool names are otherwise
|
|
173
|
+
* invisible until run time. The deploy-time capability walk reads this
|
|
174
|
+
* field to authorize a plugin-contributed tool the same way it
|
|
175
|
+
* authorizes a factory-declared tool. Empty when the plugin contributes
|
|
176
|
+
* no standalone tool (middleware-only plugins).
|
|
177
|
+
*/
|
|
178
|
+
readonly definitions: readonly ToolDeclaration[];
|
|
129
179
|
readonly [PLUGIN_MARKER]: true;
|
|
130
180
|
}
|
|
131
181
|
export type AnnotatedPluginFactory<EnvReq extends BaseEnv = BaseEnv, Result = unknown> = PluginFactory<EnvReq, Result> & AnnotatedPluginMeta;
|
|
@@ -165,6 +215,12 @@ export declare function isToolPluginInstance(value: unknown): value is Record<st
|
|
|
165
215
|
export declare function definePlugin<Result extends object, EnvReq extends BaseEnv = BaseEnv>(opts: {
|
|
166
216
|
id: string;
|
|
167
217
|
requires?: readonly string[];
|
|
218
|
+
/**
|
|
219
|
+
* Static declaration of the tool names this plugin contributes at run
|
|
220
|
+
* time. Omit for a middleware-only plugin that adds no standalone tool.
|
|
221
|
+
* See `AnnotatedPluginMeta.definitions`.
|
|
222
|
+
*/
|
|
223
|
+
definitions?: readonly ToolDeclaration[];
|
|
168
224
|
factory: PluginFactory<EnvReq, Result>;
|
|
169
225
|
}): AnnotatedPluginFactory<EnvReq, Result & {
|
|
170
226
|
kind: ToolPluginKind;
|
package/dist/tool.js
CHANGED
|
@@ -66,6 +66,23 @@ export class DuplicateToolError extends Error {
|
|
|
66
66
|
this.toolName = toolName;
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Map a tool's static approval mark to the `GrantEffect` floor its
|
|
71
|
+
* `tool:<name>` grant carries: an `ask`-marked tool floors at `ask` (its
|
|
72
|
+
* invocation must clear an approval gate), every other tool floors at
|
|
73
|
+
* `allow`.
|
|
74
|
+
*
|
|
75
|
+
* This is the single canonical derivation of a tool's authorization floor
|
|
76
|
+
* from its declaration. Both the deploy-time capability walk (hub-side)
|
|
77
|
+
* and the per-step tool authorization (sidecar-side) route through here so
|
|
78
|
+
* a pinned tool loaded in the child derives the SAME floor the walk would
|
|
79
|
+
* have derived from an inline declaration. A divergence between the two
|
|
80
|
+
* sites would let a pinned `ask` tool authorize as `allow` (or vice
|
|
81
|
+
* versa), so the mapping lives in exactly one place.
|
|
82
|
+
*/
|
|
83
|
+
export function toolApprovalEffect(declaration) {
|
|
84
|
+
return declaration.approval === "ask" ? "ask" : "allow";
|
|
85
|
+
}
|
|
69
86
|
/**
|
|
70
87
|
* Define a tool bundle factory.
|
|
71
88
|
*
|
|
@@ -75,17 +92,24 @@ export class DuplicateToolError extends Error {
|
|
|
75
92
|
* `BaseEnv`'s six core fields. The runtime `validateEnv` checks
|
|
76
93
|
* presence; the factory itself may also fail loud at construction
|
|
77
94
|
* if the env contents are structurally wrong.
|
|
95
|
+
* - `definitions` statically declares the tool names this factory
|
|
96
|
+
* contributes so callers (e.g. the deploy-time capability walk) can
|
|
97
|
+
* enumerate them without instantiating the factory.
|
|
78
98
|
* - `factory(env)` returns a `ToolBundle`. Invoked once per agent
|
|
79
99
|
* instantiation; the bundle's lifetime is tied to that agent.
|
|
80
100
|
*
|
|
81
101
|
* The returned object is the same callable as the supplied `factory`
|
|
82
|
-
* with `id
|
|
102
|
+
* with `id`, a frozen `requires` array, and a frozen `definitions`
|
|
103
|
+
* array attached.
|
|
83
104
|
*/
|
|
84
105
|
export function defineTool(opts) {
|
|
85
106
|
validateNamespacedId(opts.id);
|
|
86
107
|
const requires = Object.freeze([
|
|
87
108
|
...(opts.requires ?? []),
|
|
88
109
|
]);
|
|
110
|
+
const definitions = Object.freeze([
|
|
111
|
+
...opts.definitions,
|
|
112
|
+
]);
|
|
89
113
|
// Wrap the caller's factory rather than mutating it. A caller that
|
|
90
114
|
// shares a factory function across multiple `defineTool` calls
|
|
91
115
|
// (e.g. registering the same constructor under two ids in different
|
|
@@ -97,6 +121,7 @@ export function defineTool(opts) {
|
|
|
97
121
|
return Object.assign(wrapped, {
|
|
98
122
|
id: opts.id,
|
|
99
123
|
requires,
|
|
124
|
+
definitions,
|
|
100
125
|
});
|
|
101
126
|
}
|
|
102
127
|
/**
|
|
@@ -145,6 +170,9 @@ export function definePlugin(opts) {
|
|
|
145
170
|
const requires = Object.freeze([
|
|
146
171
|
...(opts.requires ?? []),
|
|
147
172
|
]);
|
|
173
|
+
const definitions = Object.freeze([
|
|
174
|
+
...(opts.definitions ?? []),
|
|
175
|
+
]);
|
|
148
176
|
const wrapped = (env) => {
|
|
149
177
|
const instance = opts.factory(env);
|
|
150
178
|
// Re-stamping the marker is harmless if the factory chose to set
|
|
@@ -155,6 +183,7 @@ export function definePlugin(opts) {
|
|
|
155
183
|
return Object.assign(wrapped, {
|
|
156
184
|
id: opts.id,
|
|
157
185
|
requires,
|
|
186
|
+
definitions,
|
|
158
187
|
[PLUGIN_MARKER]: true,
|
|
159
188
|
});
|
|
160
189
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intx/agent",
|
|
3
|
-
"
|
|
3
|
+
"description": "In-process agent runtime: construct an agent, send it a message, get a reply",
|
|
4
|
+
"version": "0.3.0",
|
|
4
5
|
"license": "LGPL-2.1-only",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"exports": {
|
|
@@ -16,14 +17,14 @@
|
|
|
16
17
|
}
|
|
17
18
|
},
|
|
18
19
|
"dependencies": {
|
|
19
|
-
"@intx/inference": "0.
|
|
20
|
-
"@intx/log": "0.
|
|
21
|
-
"@intx/mime": "0.
|
|
22
|
-
"@intx/types": "0.
|
|
20
|
+
"@intx/inference": "0.3.0",
|
|
21
|
+
"@intx/log": "0.3.0",
|
|
22
|
+
"@intx/mime": "0.3.0",
|
|
23
|
+
"@intx/types": "0.3.0",
|
|
23
24
|
"arktype": "^2.1.29"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
|
-
"@intx/storage-isogit": "0.
|
|
27
|
+
"@intx/storage-isogit": "0.3.0"
|
|
27
28
|
},
|
|
28
29
|
"files": [
|
|
29
30
|
"dist",
|