mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-01 01:19:38 +02:00
- biome.json (2.4.16, linter-only) wired as "lint" in all six packages - scripts/check-effect-laws.ts: Effect-native law enforcement encoding the adapted beep-effect effect-first/schema-first laws (no native JSON/switch/ sort/fetch/timers, no process.env, no throw new, no Effect.run* outside boundaries, no Schema-suffixed constants, no node:fs/path, AST-based pure-data interface detection per law 38/39) - ratcheting baseline allowlist (95 entries / 290 findings) that must shrink to documented exemptions only; stale counts fail the gate - root lint chains turbo lint + law check + native-class inventory - fix all 163 initial Biome findings: import-type style, templates, two `any`s, ten non-null assertions (librarian getService gate, A.matchRight in atoms, ensureNode returning nodes, main.tsx mount guard) Gates: lint, check:tsgo, build, test (force, 11 tasks) all green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
84 lines
2.9 KiB
TypeScript
84 lines
2.9 KiB
TypeScript
/**
|
|
* Agent CLI commands.
|
|
*
|
|
* Python reference: trustgraph-cli/trustgraph/cli/invoke_agent.py
|
|
*/
|
|
|
|
import { Effect } from "effect";
|
|
import * as Argument from "effect/unstable/cli/Argument";
|
|
import * as Command from "effect/unstable/cli/Command";
|
|
import type { CliCommandError } from "./util.js";
|
|
import { cliCommandError, withGatewayClient, } from "./util.js";
|
|
|
|
function asRecord(value: unknown): Record<string, unknown> {
|
|
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
? value as Record<string, unknown>
|
|
: {};
|
|
}
|
|
|
|
function stringProperty(source: unknown, key: string): string | undefined {
|
|
const value = asRecord(source)[key];
|
|
return typeof value === "string" ? value : undefined;
|
|
}
|
|
|
|
function booleanProperty(source: unknown, key: string): boolean | undefined {
|
|
const value = asRecord(source)[key];
|
|
return typeof value === "boolean" ? value : undefined;
|
|
}
|
|
|
|
function responseErrorMessage(source: unknown): string | undefined {
|
|
const error = asRecord(source).error;
|
|
if (typeof error === "string") return error;
|
|
return stringProperty(error, "message");
|
|
}
|
|
|
|
export const agentCommand = Command.make("agent", {
|
|
question: Argument.string("question").pipe(Argument.withDescription("Question to ask")),
|
|
}, ({ question }) =>
|
|
withGatewayClient((client, opts) =>
|
|
Effect.gen(function* () {
|
|
let streamError: CliCommandError | undefined;
|
|
|
|
yield* client.runDispatchStream(
|
|
{
|
|
scope: "flow",
|
|
flow: opts.flow,
|
|
service: "agent",
|
|
request: {
|
|
question,
|
|
user: opts.user,
|
|
collection: "default",
|
|
streaming: true,
|
|
},
|
|
},
|
|
(chunk) => {
|
|
const resp = asRecord(chunk.response);
|
|
const chunkType = stringProperty(resp, "chunk_type");
|
|
const error = chunkType === "error" ? responseErrorMessage(resp) ?? "Unknown agent error" : responseErrorMessage(resp);
|
|
if (error !== undefined) {
|
|
streamError = cliCommandError("agent", error);
|
|
return true;
|
|
}
|
|
|
|
const content = stringProperty(resp, "content") ?? "";
|
|
const messageComplete = booleanProperty(resp, "end_of_message") === true;
|
|
const dialogComplete = chunk.complete === true || booleanProperty(resp, "end_of_dialog") === true;
|
|
|
|
if (chunkType === "thought" || chunkType === "observation") {
|
|
if (content.length > 0) process.stderr.write(content);
|
|
} else if (chunkType === "answer" || chunkType === "final-answer") {
|
|
if (content.length > 0) process.stdout.write(content);
|
|
if (messageComplete || dialogComplete) process.stdout.write("\n");
|
|
}
|
|
|
|
return dialogComplete;
|
|
},
|
|
{ timeoutMs: 120_000, retries: 2 },
|
|
);
|
|
|
|
if (streamError !== undefined) {
|
|
return yield* streamError;
|
|
}
|
|
}),
|
|
),
|
|
).pipe(Command.withDescription("Ask the TrustGraph agent a question"));
|