Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions docs/modules/client/src.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,23 @@ Public barrel for the MoltZap client package.

## Public surface

### [`acquireHarnessClient`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L41)
### [`acquireHarnessClient`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L170)

_Function_

```ts
export const acquireHarnessClient = (
options: HarnessClientOptions,
): Effect.Effect<HarnessClientService, Error, Scope.Scope>
): Effect.Effect<
HarnessClientService,
Error,
Scope.Scope | KeyValueStore.KeyValueStore
>
```

Acquires one turn-ready harness connection and receive stream for the
lifetime of the enclosing scope. The private adapter owns MCP translation.
lifetime of the enclosing scope. The supplied KeyValueStore is local to the
active agent and holds only stable presentation checkpoints.

**Returns:** The scoped adapter-facing service value.

Expand Down Expand Up @@ -71,7 +76,7 @@ export interface ConversationMeta {

Describes conversation meta.

### [`HarnessClient`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L23)
### [`HarnessClient`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L43)

_Class_

Expand All @@ -84,7 +89,7 @@ export class HarnessClient extends Context.Tag("@moltzap/client/HarnessClient")<

Effect service tag consumed by runtime adapters.

### [`HarnessClientOptions`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L29)
### [`HarnessClientOptions`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L49)

_Interface_

Expand All @@ -97,44 +102,42 @@ export interface HarnessClientOptions {

Inputs needed to connect one scoped harness client.

### [`HarnessClientService`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L17)
### [`HarnessClientService`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L35)

_Interface_

```ts
export interface HarnessClientService {
/** Active identity used by adapters when rendering self-authored context. */
readonly agentId: AgentId;
/** The sole receive stream owned by this scoped client. */
readonly turns: Stream.Stream<HarnessTurn, Error>;
}
```

Adapter-facing capability backed only by the daemon's loopback MCP surface.

### [`HarnessTurn`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L7)
### [`HarnessTurn`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L29)

_Interface_

```ts
export interface HarnessTurn {
/** Existing conversation associated with every message in this turn. */
readonly conversationId: ConversationId;
/** Existing protocol messages in their daemon-provided order. */
readonly messages: readonly [Message, ...Message[]];
export interface HarnessTurn extends EnrichedInboundMessage {
/** Sends model output through the MCP reply route captured by this turn. */
readonly reply: (payload: string) => Effect.Effect<void, Error>;
}
```

One reply-capable batch emitted by the local harness daemon.
Existing adapter presentation with reply authority bound to its live turn.

### [`makeHarnessClientLayer`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L52)
### [`makeHarnessClientLayer`](https://github.com/chughtapan/moltzap/blob/main/packages/client/src/harness-client.ts#L197)

_Function_

```ts
export const makeHarnessClientLayer = (
options: HarnessClientOptions,
): Layer.Layer<HarnessClient, Error>
): Layer.Layer<HarnessClient, Error, KeyValueStore.KeyValueStore>
```

Builds the scoped runtime-adapter layer for one daemon endpoint.
Expand Down
33 changes: 18 additions & 15 deletions packages/client/src/MODULE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,23 @@ Public barrel for the MoltZap client package.

## Public surface

### [`acquireHarnessClient`](./harness-client.ts#L41)
### [`acquireHarnessClient`](./harness-client.ts#L170)

_Function_

```ts
export const acquireHarnessClient = (
options: HarnessClientOptions,
): Effect.Effect<HarnessClientService, Error, Scope.Scope>
): Effect.Effect<
HarnessClientService,
Error,
Scope.Scope | KeyValueStore.KeyValueStore
>
```

Acquires one turn-ready harness connection and receive stream for the
lifetime of the enclosing scope. The private adapter owns MCP translation.
lifetime of the enclosing scope. The supplied KeyValueStore is local to the
active agent and holds only stable presentation checkpoints.

**Returns:** The scoped adapter-facing service value.

Expand Down Expand Up @@ -66,7 +71,7 @@ export interface ConversationMeta {

Describes conversation meta.

### [`HarnessClient`](./harness-client.ts#L23)
### [`HarnessClient`](./harness-client.ts#L43)

_Class_

Expand All @@ -79,7 +84,7 @@ export class HarnessClient extends Context.Tag("@moltzap/client/HarnessClient")<

Effect service tag consumed by runtime adapters.

### [`HarnessClientOptions`](./harness-client.ts#L29)
### [`HarnessClientOptions`](./harness-client.ts#L49)

_Interface_

Expand All @@ -92,44 +97,42 @@ export interface HarnessClientOptions {

Inputs needed to connect one scoped harness client.

### [`HarnessClientService`](./harness-client.ts#L17)
### [`HarnessClientService`](./harness-client.ts#L35)

_Interface_

```ts
export interface HarnessClientService {
/** Active identity used by adapters when rendering self-authored context. */
readonly agentId: AgentId;
/** The sole receive stream owned by this scoped client. */
readonly turns: Stream.Stream<HarnessTurn, Error>;
}
```

Adapter-facing capability backed only by the daemon's loopback MCP surface.

### [`HarnessTurn`](./harness-client.ts#L7)
### [`HarnessTurn`](./harness-client.ts#L29)

_Interface_

```ts
export interface HarnessTurn {
/** Existing conversation associated with every message in this turn. */
readonly conversationId: ConversationId;
/** Existing protocol messages in their daemon-provided order. */
readonly messages: readonly [Message, ...Message[]];
export interface HarnessTurn extends EnrichedInboundMessage {
/** Sends model output through the MCP reply route captured by this turn. */
readonly reply: (payload: string) => Effect.Effect<void, Error>;
}
```

One reply-capable batch emitted by the local harness daemon.
Existing adapter presentation with reply authority bound to its live turn.

### [`makeHarnessClientLayer`](./harness-client.ts#L52)
### [`makeHarnessClientLayer`](./harness-client.ts#L197)

_Function_

```ts
export const makeHarnessClientLayer = (
options: HarnessClientOptions,
): Layer.Layer<HarnessClient, Error>
): Layer.Layer<HarnessClient, Error, KeyValueStore.KeyValueStore>
```

Builds the scoped runtime-adapter layer for one daemon endpoint.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { FileSystem, HttpClient } from "@effect/platform";
import * as KeyValueStore from "@effect/platform/KeyValueStore";
import { NodeContext, NodeHttpClient } from "@effect/platform-node";
import {
Client,
Expand Down Expand Up @@ -253,18 +254,19 @@ const expectNoUnixSocket = (socketPath: string) =>

const expectHarnessTurn = (
turn: HarnessTurn,
owner: RegisteredAgent,
peer: RegisteredAgent,
conversationId: ConversationId,
): void => {
expect(turn.conversationId).toBe(conversationId);
expect(turn.messages).toHaveLength(1);
const inbound = turn.messages[0];
if (inbound === undefined) {
throw new Error("expected one inbound harness message");
}
expect(inbound.conversationId).toBe(conversationId);
expect(inbound.senderId).toBe(peer.agentId);
expect(H.textContent(inbound)).toBe(PEER_MESSAGE);
expect(turn.sender).toEqual({ id: peer.agentId, name: peer.name });
expect(turn.text).toBe(PEER_MESSAGE);
expect(turn.isFromMe).toBe(false);
expect(turn.conversationMeta?.type).toBe("dm");
expect(new Set(turn.conversationMeta?.participants)).toEqual(
new Set([`agent:${peer.agentId}`, `agent:${owner.agentId}`]),
);
expect(turn).not.toHaveProperty("messages");
};

const expectPeerReply = (
Expand Down Expand Up @@ -379,7 +381,7 @@ const runMcpMessageRoundTrip = ({
});

const turn = yield* Fiber.join(turnFiber);
expectHarnessTurn(turn, peer, conversationId);
expectHarnessTurn(turn, owner, peer, conversationId);
yield* expectNoUnixSocket(socketPath);

yield* turn.reply(HARNESS_REPLY);
Expand Down Expand Up @@ -409,7 +411,8 @@ function runHarnessRoundTrip(owner: RegisteredAgent, peer: RegisteredAgent) {
});
const harness = yield* acquireHarnessClient({
url: harnessUrl(server).href,
});
}).pipe(Effect.provide(KeyValueStore.layerMemory));
expect(harness.agentId).toBe(owner.agentId);
const mcp = yield* acquireMcpClient(harnessUrl(server));
yield* expectNoUnixSocket(socketPath);

Expand Down
Loading
Loading