@noetic-tools/types 0.2.0 → 1.0.1
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 +4 -0
- package/dist/errors/noetic-error.d.ts +9 -1
- package/dist/errors/noetic-error.js +24 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/schemas/item.d.ts +20 -1
- package/dist/schemas/item.js +35 -19
- package/dist/types/channel.d.ts +6 -0
- package/dist/types/context.d.ts +15 -2
- package/dist/types/error.d.ts +12 -0
- package/dist/types/runtime.d.ts +7 -1
- package/dist/types/step.d.ts +32 -1
- package/dist/types/sub-harness.d.ts +273 -0
- package/dist/types/sub-harness.js +106 -0
- package/dist/util/message-helpers.d.ts +5 -1
- package/dist/util/message-helpers.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -14,6 +14,10 @@ both of which re-export the parts relevant to their public surface. Application
|
|
|
14
14
|
code normally imports these types from `@noetic-tools/core` rather than from
|
|
15
15
|
this package directly.
|
|
16
16
|
|
|
17
|
+
The `MemoryLayer` contract is additionally exported at the
|
|
18
|
+
`@noetic-tools/types/contract` subpath for memory-layer authors who want the
|
|
19
|
+
contract without the rest of the vocabulary.
|
|
20
|
+
|
|
17
21
|
## License
|
|
18
22
|
|
|
19
23
|
Apache-2.0
|
|
@@ -11,8 +11,16 @@ export declare class NoeticErrorImpl extends Error {
|
|
|
11
11
|
/**
|
|
12
12
|
* Type guard for `NoeticErrorImpl`.
|
|
13
13
|
*
|
|
14
|
+
* Uses an `instanceof` fast path, then falls back to a structural check
|
|
15
|
+
* (`Error` carrying a `noeticError.kind: string`). The fallback keeps the
|
|
16
|
+
* guard reliable when multiple copies of `@noetic-tools/types` are loaded
|
|
17
|
+
* (e.g. mixed `src`/`dist` resolution or duplicated node_modules), where
|
|
18
|
+
* `instanceof` fails across realms. The inner `kind` is deliberately not
|
|
19
|
+
* validated against the closed `NoeticError` union so errors minted by a
|
|
20
|
+
* newer copy of the package still pass (forward compatibility).
|
|
21
|
+
*
|
|
14
22
|
* @public
|
|
15
23
|
* @param e - Value to check.
|
|
16
|
-
* @returns `true` if `e` is a `NoeticErrorImpl
|
|
24
|
+
* @returns `true` if `e` is a `NoeticErrorImpl` (or structurally equivalent).
|
|
17
25
|
*/
|
|
18
26
|
export declare function isNoeticError(e: unknown): e is NoeticErrorImpl;
|
|
@@ -14,12 +14,30 @@ export class NoeticErrorImpl extends Error {
|
|
|
14
14
|
/**
|
|
15
15
|
* Type guard for `NoeticErrorImpl`.
|
|
16
16
|
*
|
|
17
|
+
* Uses an `instanceof` fast path, then falls back to a structural check
|
|
18
|
+
* (`Error` carrying a `noeticError.kind: string`). The fallback keeps the
|
|
19
|
+
* guard reliable when multiple copies of `@noetic-tools/types` are loaded
|
|
20
|
+
* (e.g. mixed `src`/`dist` resolution or duplicated node_modules), where
|
|
21
|
+
* `instanceof` fails across realms. The inner `kind` is deliberately not
|
|
22
|
+
* validated against the closed `NoeticError` union so errors minted by a
|
|
23
|
+
* newer copy of the package still pass (forward compatibility).
|
|
24
|
+
*
|
|
17
25
|
* @public
|
|
18
26
|
* @param e - Value to check.
|
|
19
|
-
* @returns `true` if `e` is a `NoeticErrorImpl
|
|
27
|
+
* @returns `true` if `e` is a `NoeticErrorImpl` (or structurally equivalent).
|
|
20
28
|
*/
|
|
21
29
|
export function isNoeticError(e) {
|
|
22
|
-
|
|
30
|
+
if (e instanceof NoeticErrorImpl) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
if (!(e instanceof Error)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (!('noeticError' in e)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const inner = e.noeticError;
|
|
40
|
+
return (typeof inner === 'object' && inner !== null && 'kind' in inner && typeof inner.kind === 'string');
|
|
23
41
|
}
|
|
24
42
|
function formatMessage(error) {
|
|
25
43
|
switch (error.kind) {
|
|
@@ -43,6 +61,10 @@ function formatMessage(error) {
|
|
|
43
61
|
return `Budget exceeded: ${error.field} limit ${error.limit}, actual ${error.actual}`;
|
|
44
62
|
case 'steering_denied':
|
|
45
63
|
return `Steering denied${error.guidance ? `: ${error.guidance}` : ''}`;
|
|
64
|
+
case 'item_schema_mismatch':
|
|
65
|
+
return error.itemType
|
|
66
|
+
? `Item type '${error.itemType}' did not match any registered item extension schema.`
|
|
67
|
+
: `Item did not match any registered ${error.category} extension schema.`;
|
|
46
68
|
case 'handle_evicted':
|
|
47
69
|
return `Subprocess handle '${error.handleId}' evicted (step '${error.stepId}'): adapter returned null for ${error.gracePeriodMs}ms`;
|
|
48
70
|
default: {
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export * from './types/runtime.js';
|
|
|
22
22
|
export * from './types/shell-adapter.js';
|
|
23
23
|
export * from './types/steering.js';
|
|
24
24
|
export * from './types/step.js';
|
|
25
|
+
export * from './types/sub-harness.js';
|
|
25
26
|
export * from './types/subprocess-adapter.js';
|
|
26
27
|
export * from './types/tool.js';
|
|
27
28
|
export * from './types/tool-context.js';
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ export * from './types/runtime.js';
|
|
|
22
22
|
export * from './types/shell-adapter.js';
|
|
23
23
|
export * from './types/steering.js';
|
|
24
24
|
export * from './types/step.js';
|
|
25
|
+
export * from './types/sub-harness.js';
|
|
25
26
|
export * from './types/subprocess-adapter.js';
|
|
26
27
|
export * from './types/tool.js';
|
|
27
28
|
export * from './types/tool-context.js';
|
package/dist/schemas/item.d.ts
CHANGED
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
* Use this at trust boundaries (loading persisted session files, accepting
|
|
12
12
|
* externally-supplied transcripts) where we need to reject garbage JSON but
|
|
13
13
|
* don't need to re-validate every provider field TypeScript already types.
|
|
14
|
+
*
|
|
15
|
+
* Extension schemas registered on the registry are **gates, not
|
|
16
|
+
* normalizers**: they validate item shape and the ORIGINAL value is returned
|
|
17
|
+
* on match. Zod transforms, defaults, and key-stripping in extension schemas
|
|
18
|
+
* are unsupported — their output is discarded. Declare pure shape validators.
|
|
14
19
|
*/
|
|
15
20
|
import { z } from 'zod';
|
|
16
21
|
import type { Item, ItemSchemaExtensions } from '../types/items.js';
|
|
@@ -18,7 +23,14 @@ import type { Item, ItemSchemaExtensions } from '../types/items.js';
|
|
|
18
23
|
export declare const ItemSchema: z.ZodCustom<Item, Item>;
|
|
19
24
|
type ItemSchemaCategory = keyof Required<ItemSchemaExtensions>;
|
|
20
25
|
export declare function mergeExtensions(a: ItemSchemaExtensions | undefined, b: ItemSchemaExtensions | undefined): ItemSchemaExtensions;
|
|
21
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* @public Runtime item validator with optional tool, memory-layer, and harness extension schemas.
|
|
28
|
+
*
|
|
29
|
+
* Extension schemas are pure shape validators (gate, not normalizer): on
|
|
30
|
+
* match the original value is returned unchanged, including fields the schema
|
|
31
|
+
* does not declare. Transforms and defaults in extension schemas are
|
|
32
|
+
* unsupported — their parsed output is never used.
|
|
33
|
+
*/
|
|
22
34
|
export declare class ItemSchemaRegistry {
|
|
23
35
|
readonly extensions: ItemSchemaExtensions;
|
|
24
36
|
readonly strictUnknownExtensions: boolean;
|
|
@@ -28,6 +40,13 @@ export declare class ItemSchemaRegistry {
|
|
|
28
40
|
extend(extensions?: ItemSchemaExtensions): ItemSchemaRegistry;
|
|
29
41
|
parse(value: unknown): Item;
|
|
30
42
|
parseMany(values: Iterable<unknown>): Item[];
|
|
43
|
+
/**
|
|
44
|
+
* Validate `value` against the schemas registered for `category` only.
|
|
45
|
+
*
|
|
46
|
+
* When no schemas are registered for the category, falls back to
|
|
47
|
+
* `parse()`. Throws a `NoeticErrorImpl` with kind `item_schema_mismatch`
|
|
48
|
+
* when schemas exist for the category and none match.
|
|
49
|
+
*/
|
|
31
50
|
parseWithCategory(value: unknown, category: ItemSchemaCategory): Item;
|
|
32
51
|
}
|
|
33
52
|
/** @public Default item schema registry. */
|
package/dist/schemas/item.js
CHANGED
|
@@ -11,8 +11,14 @@
|
|
|
11
11
|
* Use this at trust boundaries (loading persisted session files, accepting
|
|
12
12
|
* externally-supplied transcripts) where we need to reject garbage JSON but
|
|
13
13
|
* don't need to re-validate every provider field TypeScript already types.
|
|
14
|
+
*
|
|
15
|
+
* Extension schemas registered on the registry are **gates, not
|
|
16
|
+
* normalizers**: they validate item shape and the ORIGINAL value is returned
|
|
17
|
+
* on match. Zod transforms, defaults, and key-stripping in extension schemas
|
|
18
|
+
* are unsupported — their output is discarded. Declare pure shape validators.
|
|
14
19
|
*/
|
|
15
20
|
import { z } from 'zod';
|
|
21
|
+
import { NoeticErrorImpl } from '../errors/noetic-error.js';
|
|
16
22
|
function isItemLike(value) {
|
|
17
23
|
if (typeof value !== 'object' || value === null) {
|
|
18
24
|
return false;
|
|
@@ -85,15 +91,19 @@ function isKnownBaseType(type) {
|
|
|
85
91
|
type.startsWith('openrouter:'));
|
|
86
92
|
}
|
|
87
93
|
function schemaMismatch(category) {
|
|
88
|
-
return new
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
path: [],
|
|
93
|
-
},
|
|
94
|
-
]);
|
|
94
|
+
return new NoeticErrorImpl({
|
|
95
|
+
kind: 'item_schema_mismatch',
|
|
96
|
+
category,
|
|
97
|
+
});
|
|
95
98
|
}
|
|
96
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* @public Runtime item validator with optional tool, memory-layer, and harness extension schemas.
|
|
101
|
+
*
|
|
102
|
+
* Extension schemas are pure shape validators (gate, not normalizer): on
|
|
103
|
+
* match the original value is returned unchanged, including fields the schema
|
|
104
|
+
* does not declare. Transforms and defaults in extension schemas are
|
|
105
|
+
* unsupported — their parsed output is never used.
|
|
106
|
+
*/
|
|
97
107
|
export class ItemSchemaRegistry {
|
|
98
108
|
extensions;
|
|
99
109
|
strictUnknownExtensions;
|
|
@@ -116,25 +126,30 @@ export class ItemSchemaRegistry {
|
|
|
116
126
|
for (const schema of schemas) {
|
|
117
127
|
const parsed = schema.safeParse(value);
|
|
118
128
|
if (parsed.success) {
|
|
119
|
-
return
|
|
129
|
+
// Gate, not normalizer: return the original value, not the
|
|
130
|
+
// zod-stripped clone, so undeclared fields survive validation.
|
|
131
|
+
return base;
|
|
120
132
|
}
|
|
121
133
|
}
|
|
122
134
|
if (this.strictUnknownExtensions && !isKnownBaseType(base.type)) {
|
|
123
|
-
throw new
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
'type',
|
|
129
|
-
],
|
|
130
|
-
},
|
|
131
|
-
]);
|
|
135
|
+
throw new NoeticErrorImpl({
|
|
136
|
+
kind: 'item_schema_mismatch',
|
|
137
|
+
category: 'items',
|
|
138
|
+
itemType: base.type,
|
|
139
|
+
});
|
|
132
140
|
}
|
|
133
141
|
return base;
|
|
134
142
|
}
|
|
135
143
|
parseMany(values) {
|
|
136
144
|
return Array.from(values, (value) => this.parse(value));
|
|
137
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Validate `value` against the schemas registered for `category` only.
|
|
148
|
+
*
|
|
149
|
+
* When no schemas are registered for the category, falls back to
|
|
150
|
+
* `parse()`. Throws a `NoeticErrorImpl` with kind `item_schema_mismatch`
|
|
151
|
+
* when schemas exist for the category and none match.
|
|
152
|
+
*/
|
|
138
153
|
parseWithCategory(value, category) {
|
|
139
154
|
const schemas = schemasForCategory(this.extensions, category);
|
|
140
155
|
if (schemas.length === 0) {
|
|
@@ -143,7 +158,8 @@ export class ItemSchemaRegistry {
|
|
|
143
158
|
for (const schema of schemas) {
|
|
144
159
|
const parsed = schema.safeParse(value);
|
|
145
160
|
if (parsed.success) {
|
|
146
|
-
return
|
|
161
|
+
// Gate, not normalizer: validate shape, return the original value.
|
|
162
|
+
return ItemSchema.parse(value);
|
|
147
163
|
}
|
|
148
164
|
}
|
|
149
165
|
throw schemaMismatch(category);
|
package/dist/types/channel.d.ts
CHANGED
|
@@ -23,6 +23,12 @@ export interface ExternalChannel<T> extends Channel<T> {
|
|
|
23
23
|
}
|
|
24
24
|
/** @public Handle for sending messages to a channel and checking its closed state. */
|
|
25
25
|
export interface ChannelHandle<T> {
|
|
26
|
+
/**
|
|
27
|
+
* External-sender write: synchronous and never back-pressured. When a
|
|
28
|
+
* queue channel is at capacity the OLDEST item is dropped (with a warning)
|
|
29
|
+
* so external callers (HTTP handlers, CLI prompts) never block. Internal
|
|
30
|
+
* senders (`ctx.send`) get async back-pressure instead.
|
|
31
|
+
*/
|
|
26
32
|
send(value: T): void;
|
|
27
33
|
readonly closed: boolean;
|
|
28
34
|
readonly channel: Channel<T>;
|
package/dist/types/context.d.ts
CHANGED
|
@@ -135,7 +135,13 @@ export interface ContextHarness {
|
|
|
135
135
|
projectHistory(layers: MemoryLayer[], items: ReadonlyArray<import('./items.js').Item>, ctx: Context): Promise<ReadonlyArray<import('./items.js').Item>>;
|
|
136
136
|
storeLayers(layers: MemoryLayer[], response: LLMResponse, ctx: Context): Promise<void>;
|
|
137
137
|
previewRequestItems(scope?: unknown): Promise<ReadonlyArray<import('./items.js').Item>>;
|
|
138
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Internal-sender channel write. Resolves immediately unless the target
|
|
140
|
+
* queue channel is at capacity, in which case the send parks until a
|
|
141
|
+
* consumer frees a slot (back-pressure; default 30s timeout →
|
|
142
|
+
* `channel_timeout`, abort → `cancelled`).
|
|
143
|
+
*/
|
|
144
|
+
send<T>(channel: Channel<T>, value: T, ctx: Context): Promise<void>;
|
|
139
145
|
recv<T>(channel: Channel<T>, ctx: Context, opts?: {
|
|
140
146
|
timeout?: number;
|
|
141
147
|
}): Promise<T>;
|
|
@@ -193,7 +199,14 @@ export interface Context<TMemory = ContextMemory, TState = unknown> {
|
|
|
193
199
|
recv<T>(channel: Channel<T>, opts?: {
|
|
194
200
|
timeout?: number;
|
|
195
201
|
}): Promise<T>;
|
|
196
|
-
|
|
202
|
+
/**
|
|
203
|
+
* Send a value into a channel. Resolves immediately for value/topic
|
|
204
|
+
* channels and for queue channels below capacity. When a queue channel is
|
|
205
|
+
* at capacity the returned promise parks until a consumer dequeues an item
|
|
206
|
+
* (back-pressure): after the default 30s timeout it rejects with
|
|
207
|
+
* `channel_timeout`, and aborting the context rejects it with `cancelled`.
|
|
208
|
+
*/
|
|
209
|
+
send<T>(channel: Channel<T>, value: T): Promise<void>;
|
|
197
210
|
tryRecv<T>(channel: Channel<T>): T | null;
|
|
198
211
|
checkpoint(): Promise<void>;
|
|
199
212
|
complete<T>(value: T): void;
|
package/dist/types/error.d.ts
CHANGED
|
@@ -40,6 +40,18 @@ export type NoeticError = {
|
|
|
40
40
|
} | {
|
|
41
41
|
kind: 'cancelled';
|
|
42
42
|
reason?: string;
|
|
43
|
+
} | {
|
|
44
|
+
/**
|
|
45
|
+
* Raised by `ItemSchemaRegistry` when an item fails extension-schema
|
|
46
|
+
* validation: either a category item (e.g. a tool result) matches none
|
|
47
|
+
* of the schemas registered for its category, or — under
|
|
48
|
+
* `strictUnknownExtensions` — an unknown item type matches no
|
|
49
|
+
* registered extension schema. `itemType` is set for the
|
|
50
|
+
* unknown-item-type case.
|
|
51
|
+
*/
|
|
52
|
+
kind: 'item_schema_mismatch';
|
|
53
|
+
category: 'items' | 'developerMessages' | 'toolCalls' | 'toolResults';
|
|
54
|
+
itemType?: string;
|
|
43
55
|
} | {
|
|
44
56
|
kind: 'budget_exceeded';
|
|
45
57
|
field: 'cost' | 'steps' | 'duration';
|
package/dist/types/runtime.d.ts
CHANGED
|
@@ -195,7 +195,13 @@ export interface AgentHarnessContract<TParams extends Record<string, unknown> =
|
|
|
195
195
|
readonly rootCwdState: CwdState;
|
|
196
196
|
/** Update the harness root cwd. Used by the TUI when the user issues a `! cd`. */
|
|
197
197
|
setRootCwd(nextCwd: string): void;
|
|
198
|
-
|
|
198
|
+
/**
|
|
199
|
+
* Internal-sender channel write (back-pressured): resolves immediately
|
|
200
|
+
* unless the queue channel is at capacity, in which case it parks until a
|
|
201
|
+
* consumer frees a slot (30s default timeout → `channel_timeout`; context
|
|
202
|
+
* abort → `cancelled`).
|
|
203
|
+
*/
|
|
204
|
+
send<T>(channel: Channel<T>, value: T, ctx: Context): Promise<void>;
|
|
199
205
|
recv<T>(channel: Channel<T>, ctx: Context, opts?: {
|
|
200
206
|
timeout?: number;
|
|
201
207
|
}): Promise<T>;
|
package/dist/types/step.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { ModelParams, RetryPolicy, StepMeta } from './common.js';
|
|
|
4
4
|
import type { Context } from './context.js';
|
|
5
5
|
import type { NoeticError } from './error.js';
|
|
6
6
|
import type { ContextMemory, MemoryConfig, MemoryLayer, ProjectionPolicy } from './memory.js';
|
|
7
|
+
import type { SubHarness, SubHarnessKind, SubHarnessSessionPolicy, SubHarnessSettings } from './sub-harness.js';
|
|
7
8
|
import type { SubprocessAdapter } from './subprocess-adapter.js';
|
|
8
9
|
import type { Tool } from './tool.js';
|
|
9
10
|
/**
|
|
@@ -70,7 +71,7 @@ export interface SettleResult<O> {
|
|
|
70
71
|
error?: NoeticError;
|
|
71
72
|
}
|
|
72
73
|
/** @public Discriminated union of all step kinds that can be composed into an execution tree. */
|
|
73
|
-
export type Step<TMemory = ContextMemory, I = unknown, O = unknown> = StepRun<TMemory, I, O> | StepLLM<TMemory, I, O> | StepTool<TMemory, I, O> | StepBranch<TMemory, I, O> | StepFork<TMemory, I, O> | StepSpawn<TMemory, I, O> | StepProvide<TMemory, I, O> | StepLoop<TMemory, I, O> | StepEvery<TMemory, I, O>;
|
|
74
|
+
export type Step<TMemory = ContextMemory, I = unknown, O = unknown> = StepRun<TMemory, I, O> | StepLLM<TMemory, I, O> | StepSubHarness<TMemory, I, O> | StepTool<TMemory, I, O> | StepBranch<TMemory, I, O> | StepFork<TMemory, I, O> | StepSpawn<TMemory, I, O> | StepProvide<TMemory, I, O> | StepLoop<TMemory, I, O> | StepEvery<TMemory, I, O>;
|
|
74
75
|
/** @public A step that executes arbitrary async logic via a user-supplied function. */
|
|
75
76
|
export interface StepRun<TMemory = ContextMemory, I = unknown, O = unknown> {
|
|
76
77
|
kind: 'run';
|
|
@@ -102,6 +103,36 @@ export interface StepLLM<TMemory = ContextMemory, _I = unknown, O = unknown> {
|
|
|
102
103
|
/** Projection policy for this step's context window. Overrides the harness-level default. */
|
|
103
104
|
projection?: ProjectionPolicy;
|
|
104
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* A step that delegates a turn to an external coding-agent harness
|
|
108
|
+
* (Claude Code, Codex, opencode, pi). Each harness kind is a distinct
|
|
109
|
+
* `Step.kind`, but every variant shares this shape and is executed by one
|
|
110
|
+
* interpreter handler.
|
|
111
|
+
* @public
|
|
112
|
+
*/
|
|
113
|
+
export interface StepSubHarness<TMemory = ContextMemory, _I = unknown, O = unknown> {
|
|
114
|
+
/** The harness kind, equal to the backing adapter's `harnessId`. */
|
|
115
|
+
kind: SubHarnessKind;
|
|
116
|
+
id: string;
|
|
117
|
+
/**
|
|
118
|
+
* The harness adapter that runs the turn. Eager or `(ctx) => SubHarness`.
|
|
119
|
+
* Programmatic builders take it inline; the JSON hydrator resolves it from
|
|
120
|
+
* the workflow's harness registry and inlines it here.
|
|
121
|
+
*/
|
|
122
|
+
harness: Lazy<SubHarness, TMemory>;
|
|
123
|
+
/** Turn prompt. Eager string or `(ctx) => string` getter. */
|
|
124
|
+
prompt: Lazy<string, TMemory>;
|
|
125
|
+
/** Shared harness settings (model, permission mode, …). */
|
|
126
|
+
settings?: SubHarnessSettings;
|
|
127
|
+
/** System instructions applied on the first message of a fresh session. */
|
|
128
|
+
instructions?: Lazy<string | undefined, TMemory>;
|
|
129
|
+
/** When set, the assistant text is JSON-parsed and validated against this schema. */
|
|
130
|
+
output?: ZodType<O>;
|
|
131
|
+
/** Session reuse + teardown policy across steps. */
|
|
132
|
+
session?: SubHarnessSessionPolicy;
|
|
133
|
+
/** Controls framework event emission for this step. Defaults to `true`. */
|
|
134
|
+
emit?: boolean | ((eventType: string, data: Record<string, unknown>) => boolean);
|
|
135
|
+
}
|
|
105
136
|
/** @public A step that invokes a single tool directly, bypassing the LLM. */
|
|
106
137
|
export interface StepTool<_TMemory = ContextMemory, I = unknown, O = unknown> {
|
|
107
138
|
kind: 'tool';
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coding-agent harness contract.
|
|
3
|
+
*
|
|
4
|
+
* A "harness" here is a pluggable backend that drives an external agentic
|
|
5
|
+
* coding tool — Claude Code, Codex, opencode, pi — as a Noetic step. It is the
|
|
6
|
+
* direct analogue of the `MemoryLayer` contract: defined in the dependency-free
|
|
7
|
+
* `@noetic-tools/types` foundation so both `@noetic-tools/core` (which executes
|
|
8
|
+
* harness steps) and the per-tool `@noetic-tools/sub-harness-*` packages (which
|
|
9
|
+
* implement them) can depend on it without forming a cycle.
|
|
10
|
+
*
|
|
11
|
+
* Modelled on Vercel's `HarnessV1` spec: a tagged spec version, a small set of
|
|
12
|
+
* descriptive fields, and a single `doStart` entry point that yields a session.
|
|
13
|
+
* Optional capabilities are signalled by the presence of optional methods, not
|
|
14
|
+
* a static capabilities object — an adapter that cannot satisfy a request
|
|
15
|
+
* throws {@link SubHarnessCapabilityError} from the relevant method.
|
|
16
|
+
*/
|
|
17
|
+
import { z } from 'zod';
|
|
18
|
+
import type { TokenUsage } from './common.js';
|
|
19
|
+
import type { FsAdapter } from './fs-adapter.js';
|
|
20
|
+
import type { Item } from './items.js';
|
|
21
|
+
import type { ShellAdapter } from './shell-adapter.js';
|
|
22
|
+
import type { SubprocessAdapter } from './subprocess-adapter.js';
|
|
23
|
+
/**
|
|
24
|
+
* The set of harness step kinds. Each value is a distinct `Step.kind`, so a
|
|
25
|
+
* `step.claudeCode(...)` and a `step.codex(...)` are separate, individually
|
|
26
|
+
* typed step variants — while the interpreter routes all of them through a
|
|
27
|
+
* single shared `executeSubHarness` handler.
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export declare const SubHarnessKind: {
|
|
31
|
+
readonly ClaudeCode: "claude-code";
|
|
32
|
+
readonly Codex: "codex";
|
|
33
|
+
readonly Opencode: "opencode";
|
|
34
|
+
readonly Pi: "pi";
|
|
35
|
+
};
|
|
36
|
+
/** @public Union of all harness step kinds. */
|
|
37
|
+
export type SubHarnessKind = (typeof SubHarnessKind)[keyof typeof SubHarnessKind];
|
|
38
|
+
/** @public Ordered list of every harness kind — the single source of truth consumed by the JSON schema and the interpreter. */
|
|
39
|
+
export declare const SUB_HARNESS_KINDS: ReadonlyArray<SubHarnessKind>;
|
|
40
|
+
/**
|
|
41
|
+
* Settings shared by every harness step. Tool-specific knobs that don't map to
|
|
42
|
+
* a shared concept go through `extra`, which each adapter interprets (and may
|
|
43
|
+
* reject with {@link SubHarnessCapabilityError}).
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
export interface SubHarnessSettings {
|
|
47
|
+
/** Model identifier for the underlying agent (e.g. `claude-opus-4-8`). */
|
|
48
|
+
model?: string;
|
|
49
|
+
/** Permission posture for tool/file mutations the agent attempts. */
|
|
50
|
+
permissionMode?: 'default' | 'plan' | 'acceptEdits' | 'bypassPermissions';
|
|
51
|
+
/** Hard cap on internal agent turns before it must yield. */
|
|
52
|
+
maxTurns?: number;
|
|
53
|
+
/** Restrict the agent to this set of built-in tool names. */
|
|
54
|
+
allowedTools?: ReadonlyArray<string>;
|
|
55
|
+
/** Tool-specific passthrough options interpreted by the adapter. */
|
|
56
|
+
extra?: Record<string, unknown>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Controls how a harness session is reused and torn down across steps.
|
|
60
|
+
* @public
|
|
61
|
+
*/
|
|
62
|
+
export interface SubHarnessSessionPolicy {
|
|
63
|
+
/**
|
|
64
|
+
* Reuse a live session keyed by this id across multiple harness steps. When
|
|
65
|
+
* omitted, each step gets a fresh session that is stopped on completion.
|
|
66
|
+
*/
|
|
67
|
+
reuse?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Lifecycle action when the step completes. `'stop'` (default) persists state
|
|
70
|
+
* and stops the runtime; `'detach'` parks it for later resume; `'destroy'`
|
|
71
|
+
* discards it with no resume state.
|
|
72
|
+
*/
|
|
73
|
+
onComplete?: 'stop' | 'detach' | 'destroy';
|
|
74
|
+
}
|
|
75
|
+
/** @public Why an agentic turn ended. */
|
|
76
|
+
export type SubHarnessFinishReason = 'stop' | 'length' | 'aborted' | 'error' | 'tool-calls';
|
|
77
|
+
/**
|
|
78
|
+
* Runtime validation schema for {@link SubHarnessStreamPart}. Adapters that move
|
|
79
|
+
* events across a process or transport boundary (e.g. a sandbox bridge)
|
|
80
|
+
* validate with this before forwarding.
|
|
81
|
+
* @public
|
|
82
|
+
*/
|
|
83
|
+
export declare const SubHarnessStreamPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
84
|
+
type: z.ZodLiteral<"stream-start">;
|
|
85
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
86
|
+
type: z.ZodLiteral<"text-delta">;
|
|
87
|
+
delta: z.ZodString;
|
|
88
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
89
|
+
type: z.ZodLiteral<"reasoning-delta">;
|
|
90
|
+
delta: z.ZodString;
|
|
91
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
92
|
+
type: z.ZodLiteral<"tool-call">;
|
|
93
|
+
toolCallId: z.ZodString;
|
|
94
|
+
toolName: z.ZodString;
|
|
95
|
+
input: z.ZodUnknown;
|
|
96
|
+
providerExecuted: z.ZodOptional<z.ZodBoolean>;
|
|
97
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
98
|
+
type: z.ZodLiteral<"tool-result">;
|
|
99
|
+
toolCallId: z.ZodString;
|
|
100
|
+
toolName: z.ZodString;
|
|
101
|
+
output: z.ZodUnknown;
|
|
102
|
+
isError: z.ZodOptional<z.ZodBoolean>;
|
|
103
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
104
|
+
type: z.ZodLiteral<"file-change">;
|
|
105
|
+
path: z.ZodOptional<z.ZodString>;
|
|
106
|
+
summary: z.ZodOptional<z.ZodString>;
|
|
107
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
108
|
+
type: z.ZodLiteral<"finish">;
|
|
109
|
+
finishReason: z.ZodEnum<{
|
|
110
|
+
error: "error";
|
|
111
|
+
length: "length";
|
|
112
|
+
aborted: "aborted";
|
|
113
|
+
stop: "stop";
|
|
114
|
+
"tool-calls": "tool-calls";
|
|
115
|
+
}>;
|
|
116
|
+
usage: z.ZodOptional<z.ZodObject<{
|
|
117
|
+
input: z.ZodNumber;
|
|
118
|
+
output: z.ZodNumber;
|
|
119
|
+
total: z.ZodOptional<z.ZodNumber>;
|
|
120
|
+
cached: z.ZodOptional<z.ZodNumber>;
|
|
121
|
+
}, z.core.$strip>>;
|
|
122
|
+
cost: z.ZodOptional<z.ZodNumber>;
|
|
123
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
124
|
+
type: z.ZodLiteral<"error">;
|
|
125
|
+
error: z.ZodString;
|
|
126
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
127
|
+
type: z.ZodLiteral<"raw">;
|
|
128
|
+
value: z.ZodUnknown;
|
|
129
|
+
}, z.core.$strip>], "type">;
|
|
130
|
+
/**
|
|
131
|
+
* A single event emitted by a harness during a turn. Mirrors the model-stream
|
|
132
|
+
* primitives so the interpreter can forward them as framework events with
|
|
133
|
+
* minimal translation. Adapter-specific metadata rides on `raw`.
|
|
134
|
+
* @public
|
|
135
|
+
*/
|
|
136
|
+
export type SubHarnessStreamPart = z.infer<typeof SubHarnessStreamPartSchema>;
|
|
137
|
+
/**
|
|
138
|
+
* The workspace surface a harness session may touch during a turn. A focused
|
|
139
|
+
* subset of {@link Context} so adapters don't depend on the full runtime type.
|
|
140
|
+
* @public
|
|
141
|
+
*/
|
|
142
|
+
export interface SubHarnessRunContext {
|
|
143
|
+
/** Working directory the agent runs in (resolved from `ctx.cwdState.cwd`). */
|
|
144
|
+
readonly cwd: string;
|
|
145
|
+
readonly fs: FsAdapter;
|
|
146
|
+
readonly shell: ShellAdapter;
|
|
147
|
+
readonly subprocess: SubprocessAdapter;
|
|
148
|
+
/** Conversation thread id, for adapters that persist per-thread session state. */
|
|
149
|
+
readonly threadId: string;
|
|
150
|
+
/** Abort signal for the surrounding execution. */
|
|
151
|
+
readonly signal?: AbortSignal;
|
|
152
|
+
}
|
|
153
|
+
/** @public Opaque, adapter-defined state for resuming a stopped/detached session. */
|
|
154
|
+
export interface SubHarnessResumeState {
|
|
155
|
+
readonly harnessId: string;
|
|
156
|
+
readonly sessionId: string;
|
|
157
|
+
readonly state: unknown;
|
|
158
|
+
}
|
|
159
|
+
/** @public Opaque, adapter-defined state for continuing a turn frozen mid-flight. */
|
|
160
|
+
export interface SubHarnessContinueState {
|
|
161
|
+
readonly harnessId: string;
|
|
162
|
+
readonly sessionId: string;
|
|
163
|
+
readonly state: unknown;
|
|
164
|
+
}
|
|
165
|
+
/** @public Options handed to {@link SubHarness.doStart}. */
|
|
166
|
+
export interface SubHarnessStartOptions<TSettings = SubHarnessSettings> {
|
|
167
|
+
/** Per-step settings (model, permission mode, …). */
|
|
168
|
+
settings?: TSettings;
|
|
169
|
+
/**
|
|
170
|
+
* System instructions applied once on the first message of a fresh session.
|
|
171
|
+
* Never re-applied on resume.
|
|
172
|
+
*/
|
|
173
|
+
instructions?: string;
|
|
174
|
+
/**
|
|
175
|
+
* Prior conversation history (from earlier LLM/sub-harness steps and turns)
|
|
176
|
+
* used to seed a fresh session so the agent has full context of the
|
|
177
|
+
* conversation so far. Empty for the very first step of a run.
|
|
178
|
+
*/
|
|
179
|
+
history?: ReadonlyArray<Item>;
|
|
180
|
+
/** The workspace surface for this run. */
|
|
181
|
+
ctx: SubHarnessRunContext;
|
|
182
|
+
/** Resume a previously stopped/detached session. */
|
|
183
|
+
resumeFrom?: SubHarnessResumeState;
|
|
184
|
+
/** Continue a turn previously frozen via {@link SubHarnessSession.doSuspendTurn}. */
|
|
185
|
+
continueFrom?: SubHarnessContinueState;
|
|
186
|
+
signal?: AbortSignal;
|
|
187
|
+
}
|
|
188
|
+
/** @public Options for a single agentic turn. */
|
|
189
|
+
export interface SubHarnessPromptTurnOptions {
|
|
190
|
+
/** Fresh turn input only — the session owns conversation history. */
|
|
191
|
+
prompt: string;
|
|
192
|
+
/** Sink for stream events produced during the turn. */
|
|
193
|
+
emit: (part: SubHarnessStreamPart) => void;
|
|
194
|
+
signal?: AbortSignal;
|
|
195
|
+
}
|
|
196
|
+
/** @public Options for continuing a turn frozen mid-flight. */
|
|
197
|
+
export interface SubHarnessContinueTurnOptions {
|
|
198
|
+
emit: (part: SubHarnessStreamPart) => void;
|
|
199
|
+
signal?: AbortSignal;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Result of a completed agentic turn. The interpreter appends `items` to the
|
|
203
|
+
* item log, charges `usage`/`cost`, and returns `text` (or parses it through
|
|
204
|
+
* the step's output schema).
|
|
205
|
+
* @public
|
|
206
|
+
*/
|
|
207
|
+
export interface SubHarnessTurnResult {
|
|
208
|
+
/** Noetic Items produced this turn (assistant message, tool calls/results). */
|
|
209
|
+
items: Item[];
|
|
210
|
+
/** Final assistant text of the turn. */
|
|
211
|
+
text: string;
|
|
212
|
+
usage?: TokenUsage;
|
|
213
|
+
cost?: number;
|
|
214
|
+
finishReason?: SubHarnessFinishReason;
|
|
215
|
+
/** Adapter-specific metadata (peer to provider metadata, not a subtype). */
|
|
216
|
+
harnessMetadata?: Record<string, unknown>;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Describes a tool the underlying agent executes natively, mapped to a shared
|
|
220
|
+
* `commonName` so consumers can recognise "the same kind of tool" across
|
|
221
|
+
* harnesses (Claude's `Bash`, Codex's `shell`, pi's `bash` → `shell`).
|
|
222
|
+
* @public
|
|
223
|
+
*/
|
|
224
|
+
export interface SubHarnessBuiltinTool {
|
|
225
|
+
/** The agent's native tool name. */
|
|
226
|
+
readonly nativeName: string;
|
|
227
|
+
/** Shared cross-harness name, when one exists. */
|
|
228
|
+
readonly commonName?: string;
|
|
229
|
+
readonly description?: string;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* A live harness session: one workspace + one conversation history + one
|
|
233
|
+
* running runtime, kept across turns by the interpreter.
|
|
234
|
+
* @public
|
|
235
|
+
*/
|
|
236
|
+
export interface SubHarnessSession {
|
|
237
|
+
readonly sessionId: string;
|
|
238
|
+
/** True when this session was resumed rather than freshly started. */
|
|
239
|
+
readonly isResume: boolean;
|
|
240
|
+
/** The model the session resolved to, when the runtime reports it. */
|
|
241
|
+
readonly modelId?: string;
|
|
242
|
+
/** Run one agentic turn to completion. */
|
|
243
|
+
doPromptTurn(opts: SubHarnessPromptTurnOptions): Promise<SubHarnessTurnResult>;
|
|
244
|
+
/** Continue a turn previously frozen via {@link doSuspendTurn}. */
|
|
245
|
+
doContinueTurn?(opts: SubHarnessContinueTurnOptions): Promise<SubHarnessTurnResult>;
|
|
246
|
+
/** Freeze the current turn at a precise event cursor; runtime stays alive. */
|
|
247
|
+
doSuspendTurn?(): Promise<SubHarnessContinueState>;
|
|
248
|
+
/** Manually compact conversation history. Throws {@link SubHarnessCapabilityError} if unsupported. */
|
|
249
|
+
doCompact?(customInstructions?: string): Promise<void>;
|
|
250
|
+
/** Park the session between turns; runtime stays alive. */
|
|
251
|
+
doDetach?(): Promise<SubHarnessResumeState>;
|
|
252
|
+
/** Persist state and stop the runtime. */
|
|
253
|
+
doStop(): Promise<SubHarnessResumeState>;
|
|
254
|
+
/** Stop the runtime with no resume state. */
|
|
255
|
+
doDestroy?(): Promise<void>;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* A coding-agent harness. Each `@noetic-tools/sub-harness-*` package exports a
|
|
259
|
+
* factory returning one of these (e.g. `claudeCode({ model })`).
|
|
260
|
+
* @public
|
|
261
|
+
*/
|
|
262
|
+
export interface SubHarness<TSettings = SubHarnessSettings> {
|
|
263
|
+
/** Spec tag for forward-compatibility. */
|
|
264
|
+
readonly specificationVersion: 'harness-v1';
|
|
265
|
+
/** Stable identifier, equal to the step kind it backs (e.g. `claude-code`). */
|
|
266
|
+
readonly harnessId: SubHarnessKind;
|
|
267
|
+
/** Tools the underlying agent executes natively. */
|
|
268
|
+
readonly builtinTools?: ReadonlyArray<SubHarnessBuiltinTool>;
|
|
269
|
+
/** Validates `resumeFrom`/`continueFrom` payloads, when the adapter persists them. */
|
|
270
|
+
readonly lifecycleStateSchema?: z.ZodType;
|
|
271
|
+
/** Start (or resume/continue) a session. */
|
|
272
|
+
doStart(opts: SubHarnessStartOptions<TSettings>): Promise<SubHarnessSession>;
|
|
273
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coding-agent harness contract.
|
|
3
|
+
*
|
|
4
|
+
* A "harness" here is a pluggable backend that drives an external agentic
|
|
5
|
+
* coding tool — Claude Code, Codex, opencode, pi — as a Noetic step. It is the
|
|
6
|
+
* direct analogue of the `MemoryLayer` contract: defined in the dependency-free
|
|
7
|
+
* `@noetic-tools/types` foundation so both `@noetic-tools/core` (which executes
|
|
8
|
+
* harness steps) and the per-tool `@noetic-tools/sub-harness-*` packages (which
|
|
9
|
+
* implement them) can depend on it without forming a cycle.
|
|
10
|
+
*
|
|
11
|
+
* Modelled on Vercel's `HarnessV1` spec: a tagged spec version, a small set of
|
|
12
|
+
* descriptive fields, and a single `doStart` entry point that yields a session.
|
|
13
|
+
* Optional capabilities are signalled by the presence of optional methods, not
|
|
14
|
+
* a static capabilities object — an adapter that cannot satisfy a request
|
|
15
|
+
* throws {@link SubHarnessCapabilityError} from the relevant method.
|
|
16
|
+
*/
|
|
17
|
+
import { z } from 'zod';
|
|
18
|
+
//#region Step-kind discriminator
|
|
19
|
+
/**
|
|
20
|
+
* The set of harness step kinds. Each value is a distinct `Step.kind`, so a
|
|
21
|
+
* `step.claudeCode(...)` and a `step.codex(...)` are separate, individually
|
|
22
|
+
* typed step variants — while the interpreter routes all of them through a
|
|
23
|
+
* single shared `executeSubHarness` handler.
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export const SubHarnessKind = {
|
|
27
|
+
ClaudeCode: 'claude-code',
|
|
28
|
+
Codex: 'codex',
|
|
29
|
+
Opencode: 'opencode',
|
|
30
|
+
Pi: 'pi',
|
|
31
|
+
};
|
|
32
|
+
/** @public Ordered list of every harness kind — the single source of truth consumed by the JSON schema and the interpreter. */
|
|
33
|
+
export const SUB_HARNESS_KINDS = [
|
|
34
|
+
SubHarnessKind.ClaudeCode,
|
|
35
|
+
SubHarnessKind.Codex,
|
|
36
|
+
SubHarnessKind.Opencode,
|
|
37
|
+
SubHarnessKind.Pi,
|
|
38
|
+
];
|
|
39
|
+
const HarnessFinishReasonSchema = z.enum([
|
|
40
|
+
'stop',
|
|
41
|
+
'length',
|
|
42
|
+
'aborted',
|
|
43
|
+
'error',
|
|
44
|
+
'tool-calls',
|
|
45
|
+
]);
|
|
46
|
+
const TokenUsageSchema = z.object({
|
|
47
|
+
input: z.number(),
|
|
48
|
+
output: z.number(),
|
|
49
|
+
total: z.number().optional(),
|
|
50
|
+
cached: z.number().optional(),
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* Runtime validation schema for {@link SubHarnessStreamPart}. Adapters that move
|
|
54
|
+
* events across a process or transport boundary (e.g. a sandbox bridge)
|
|
55
|
+
* validate with this before forwarding.
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
export const SubHarnessStreamPartSchema = z.discriminatedUnion('type', [
|
|
59
|
+
z.object({
|
|
60
|
+
type: z.literal('stream-start'),
|
|
61
|
+
}),
|
|
62
|
+
z.object({
|
|
63
|
+
type: z.literal('text-delta'),
|
|
64
|
+
delta: z.string(),
|
|
65
|
+
}),
|
|
66
|
+
z.object({
|
|
67
|
+
type: z.literal('reasoning-delta'),
|
|
68
|
+
delta: z.string(),
|
|
69
|
+
}),
|
|
70
|
+
z.object({
|
|
71
|
+
type: z.literal('tool-call'),
|
|
72
|
+
toolCallId: z.string(),
|
|
73
|
+
toolName: z.string(),
|
|
74
|
+
input: z.unknown(),
|
|
75
|
+
/** True when the underlying agent executed the tool itself (vs. host dispatch). */
|
|
76
|
+
providerExecuted: z.boolean().optional(),
|
|
77
|
+
}),
|
|
78
|
+
z.object({
|
|
79
|
+
type: z.literal('tool-result'),
|
|
80
|
+
toolCallId: z.string(),
|
|
81
|
+
toolName: z.string(),
|
|
82
|
+
output: z.unknown(),
|
|
83
|
+
isError: z.boolean().optional(),
|
|
84
|
+
}),
|
|
85
|
+
z.object({
|
|
86
|
+
type: z.literal('file-change'),
|
|
87
|
+
path: z.string().optional(),
|
|
88
|
+
summary: z.string().optional(),
|
|
89
|
+
}),
|
|
90
|
+
z.object({
|
|
91
|
+
type: z.literal('finish'),
|
|
92
|
+
finishReason: HarnessFinishReasonSchema,
|
|
93
|
+
usage: TokenUsageSchema.optional(),
|
|
94
|
+
cost: z.number().optional(),
|
|
95
|
+
}),
|
|
96
|
+
z.object({
|
|
97
|
+
type: z.literal('error'),
|
|
98
|
+
error: z.string(),
|
|
99
|
+
}),
|
|
100
|
+
/** Adapter-specific passthrough for events with no canonical mapping. */
|
|
101
|
+
z.object({
|
|
102
|
+
type: z.literal('raw'),
|
|
103
|
+
value: z.unknown(),
|
|
104
|
+
}),
|
|
105
|
+
]);
|
|
106
|
+
//#endregion
|
|
@@ -2,7 +2,11 @@ import type { LLMResponse } from '../types/common.js';
|
|
|
2
2
|
import type { Context } from '../types/context.js';
|
|
3
3
|
import type { InputMessageItem, Item, MessageItem } from '../types/items.js';
|
|
4
4
|
export declare function isAssistantMessage(item: unknown): item is MessageItem;
|
|
5
|
-
|
|
5
|
+
/** @public Input message item narrowed to the `user` role. */
|
|
6
|
+
export type UserMessageItem = InputMessageItem & {
|
|
7
|
+
readonly role: 'user';
|
|
8
|
+
};
|
|
9
|
+
export declare function isUserMessage(item: unknown): item is UserMessageItem;
|
|
6
10
|
export declare function isOutputText(part: {
|
|
7
11
|
type: string;
|
|
8
12
|
}): part is {
|
|
@@ -28,7 +28,7 @@ export function isTextPart(part) {
|
|
|
28
28
|
/** Extracts assistant/output text from items for memory buffering (one string per message). */
|
|
29
29
|
export function collectOutputText(items) {
|
|
30
30
|
return items
|
|
31
|
-
.filter(
|
|
31
|
+
.filter(isAssistantMessage)
|
|
32
32
|
.map((i) => i.content
|
|
33
33
|
.filter(isOutputText)
|
|
34
34
|
.map((c) => c.text)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noetic-tools/types",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Foundational type contracts and primitives shared across the Noetic framework (items, LLM config, adapters, steering, errors).",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"scripts": {
|
|
61
61
|
"build": "bunx tsc -p tsconfig.build.json && bun scripts/add-js-extensions.ts",
|
|
62
62
|
"verify:esm": "bun scripts/verify-node-esm.ts",
|
|
63
|
-
"prepublishOnly": "rm -rf dist && bun run build && bun run verify:esm",
|
|
63
|
+
"prepublishOnly": "rm -rf dist && bun run build && bun run verify:esm && bun scripts/strip-dev-conditions.ts",
|
|
64
64
|
"test": "bun test",
|
|
65
65
|
"test:coverage": "bun test --coverage --coverage-reporter=text --coverage-reporter=lcov",
|
|
66
66
|
"test:ci": "bun test --coverage --coverage-reporter=lcov",
|