faces-cli 1.7.1 → 1.7.2
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/dist/commands/chat/chat.d.ts +3 -1
- package/dist/commands/chat/chat.js +29 -4
- package/dist/routing.d.ts +9 -0
- package/dist/routing.js +18 -1
- package/oclif.manifest.json +626 -614
- package/package.json +1 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base.js';
|
|
2
2
|
export default class ChatChat extends BaseCommand {
|
|
3
3
|
static description: string;
|
|
4
|
+
static examples: string[];
|
|
4
5
|
static flags: {
|
|
5
6
|
message: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
7
|
llm: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
formula: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
9
|
system: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
10
|
stream: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
11
|
'max-tokens': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -16,7 +18,7 @@ export default class ChatChat extends BaseCommand {
|
|
|
16
18
|
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
19
|
};
|
|
18
20
|
static args: {
|
|
19
|
-
face_username: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
21
|
+
face_username: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
20
22
|
};
|
|
21
23
|
run(): Promise<unknown>;
|
|
22
24
|
private oauthHint;
|
|
@@ -3,13 +3,19 @@ import fs from 'node:fs';
|
|
|
3
3
|
import { BaseCommand } from '../../base.js';
|
|
4
4
|
import { FacesAPIError } from '../../client.js';
|
|
5
5
|
import { extractStreamDelta } from '../../utils.js';
|
|
6
|
-
import { resolveEndpoint, MESSAGES_ENDPOINT, RESPONSES_ENDPOINT } from '../../routing.js';
|
|
6
|
+
import { resolveEndpoint, MESSAGES_ENDPOINT, RESPONSES_ENDPOINT, isCompositeFormula, faceSpecOf, llmFromArg } from '../../routing.js';
|
|
7
7
|
export default class ChatChat extends BaseCommand {
|
|
8
8
|
static description = 'Chat via a face. Auto-routes to the correct API endpoint based on the model catalog.';
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> <%= command.id %> socrates -m "What is virtue?"',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> "(socrates | nietzsche)@claude-sonnet-4-6" -m "What is virtue?"',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> --formula "socrates | nietzsche" --llm claude-sonnet-4-6 -m "What is virtue?"',
|
|
13
|
+
];
|
|
9
14
|
static flags = {
|
|
10
15
|
...BaseCommand.baseFlags,
|
|
11
16
|
message: Flags.string({ char: 'm', description: 'User message (repeatable)', multiple: true, required: false }),
|
|
12
17
|
llm: Flags.string({ description: 'LLM override (e.g. gpt-4o-mini, claude-sonnet-4-6)' }),
|
|
18
|
+
formula: Flags.string({ description: 'Compose a run-time composite from your own faces, e.g. "socrates | nietzsche" (operators: | & ^ -). Requires --llm.' }),
|
|
13
19
|
system: Flags.string({ description: 'System prompt / instructions' }),
|
|
14
20
|
stream: Flags.boolean({ description: 'Stream the response', default: false }),
|
|
15
21
|
'max-tokens': Flags.integer({ description: 'Max tokens' }),
|
|
@@ -19,20 +25,39 @@ export default class ChatChat extends BaseCommand {
|
|
|
19
25
|
'oauth-only': Flags.boolean({ description: 'Prevent fallback to paid system key (use OAuth only)', default: false }),
|
|
20
26
|
};
|
|
21
27
|
static args = {
|
|
22
|
-
face_username: Args.string({
|
|
28
|
+
face_username: Args.string({
|
|
29
|
+
description: 'Face alias (alias@model, owner:alias@model for a published face, or a composite formula like "(a | b)@model"). Omit when using --formula.',
|
|
30
|
+
required: false,
|
|
31
|
+
}),
|
|
23
32
|
};
|
|
24
33
|
async run() {
|
|
25
34
|
const { args, flags } = await this.parse(ChatChat);
|
|
26
35
|
const client = this.makeClient(flags);
|
|
27
36
|
// Build model string
|
|
28
37
|
let model;
|
|
29
|
-
if (flags.
|
|
30
|
-
|
|
38
|
+
if (flags.formula) {
|
|
39
|
+
if (args.face_username)
|
|
40
|
+
this.error('Pass either a face argument or --formula, not both.');
|
|
41
|
+
if (!flags.llm)
|
|
42
|
+
this.error('--formula needs a model. Add --llm <model>, e.g. --llm claude-sonnet-4-6.');
|
|
43
|
+
model = `(${flags.formula.trim()})@${flags.llm}`;
|
|
44
|
+
}
|
|
45
|
+
else if (!args.face_username) {
|
|
46
|
+
this.error('Provide a face (alias, owner:alias, or a composite formula), or use --formula.');
|
|
47
|
+
}
|
|
48
|
+
else if (flags.llm) {
|
|
49
|
+
const base = faceSpecOf(args.face_username);
|
|
31
50
|
model = `${base}@${flags.llm}`;
|
|
32
51
|
}
|
|
33
52
|
else {
|
|
34
53
|
model = args.face_username;
|
|
35
54
|
}
|
|
55
|
+
// A run-time composite has no stored default_model — require an explicit @model (rule #1).
|
|
56
|
+
if (isCompositeFormula(model) && !llmFromArg(model)) {
|
|
57
|
+
const spec = faceSpecOf(model);
|
|
58
|
+
this.error(`Composite face '${spec}' has no default model. Specify one explicitly, ` +
|
|
59
|
+
`e.g. '${spec}@claude-sonnet-4-6', or pass --llm <model>.`);
|
|
60
|
+
}
|
|
36
61
|
// Collect user messages
|
|
37
62
|
const userMessages = [];
|
|
38
63
|
if (flags.file) {
|
package/dist/routing.d.ts
CHANGED
|
@@ -11,6 +11,15 @@ export interface RouteInfo {
|
|
|
11
11
|
}
|
|
12
12
|
/** Split `alias@llm` → llm; bare `alias` → undefined. */
|
|
13
13
|
export declare function llmFromArg(modelArg: string): string | undefined;
|
|
14
|
+
/** The face-spec (everything left of the trailing `@model`), e.g. `(a | b)@x` → `(a | b)`. */
|
|
15
|
+
export declare function faceSpecOf(modelArg: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* True when a model arg's face-spec is a run-time composite formula, i.e. it
|
|
18
|
+
* contains a set operator (`| & ^`), grouping parens, or a space-delimited `-`
|
|
19
|
+
* difference. None of these characters are legal in an alias (`^[a-z0-9-]+$`) or
|
|
20
|
+
* in `owner:alias`, so detection is unambiguous. Mirrors the backend's check.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isCompositeFormula(modelArg: string): boolean;
|
|
14
23
|
/**
|
|
15
24
|
* Decide which API endpoint a chat request should be posted to, driven entirely
|
|
16
25
|
* by the model catalog (GET /v1/models). For a bare alias we resolve the face's
|
package/dist/routing.js
CHANGED
|
@@ -88,6 +88,21 @@ export function llmFromArg(modelArg) {
|
|
|
88
88
|
const i = modelArg.lastIndexOf('@');
|
|
89
89
|
return i >= 0 ? modelArg.slice(i + 1) : undefined;
|
|
90
90
|
}
|
|
91
|
+
/** The face-spec (everything left of the trailing `@model`), e.g. `(a | b)@x` → `(a | b)`. */
|
|
92
|
+
export function faceSpecOf(modelArg) {
|
|
93
|
+
const i = modelArg.lastIndexOf('@');
|
|
94
|
+
return i >= 0 ? modelArg.slice(0, i) : modelArg;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* True when a model arg's face-spec is a run-time composite formula, i.e. it
|
|
98
|
+
* contains a set operator (`| & ^`), grouping parens, or a space-delimited `-`
|
|
99
|
+
* difference. None of these characters are legal in an alias (`^[a-z0-9-]+$`) or
|
|
100
|
+
* in `owner:alias`, so detection is unambiguous. Mirrors the backend's check.
|
|
101
|
+
*/
|
|
102
|
+
export function isCompositeFormula(modelArg) {
|
|
103
|
+
const spec = faceSpecOf(modelArg).trim();
|
|
104
|
+
return /[|&^()]/.test(spec) || /\S\s+\S/.test(spec);
|
|
105
|
+
}
|
|
91
106
|
/**
|
|
92
107
|
* Decide which API endpoint a chat request should be posted to, driven entirely
|
|
93
108
|
* by the model catalog (GET /v1/models). For a bare alias we resolve the face's
|
|
@@ -95,7 +110,9 @@ export function llmFromArg(modelArg) {
|
|
|
95
110
|
*/
|
|
96
111
|
export async function resolveEndpoint(client, modelArg) {
|
|
97
112
|
let llm = llmFromArg(modelArg);
|
|
98
|
-
|
|
113
|
+
// A composite formula has no stored default_model and isn't a catalog face, so
|
|
114
|
+
// never attempt an alias lookup — route purely off the explicit `@model`.
|
|
115
|
+
if (!llm && !isCompositeFormula(modelArg)) {
|
|
99
116
|
const alias = modelArg.split('@')[0];
|
|
100
117
|
llm = defaultModelFromCatalog(alias);
|
|
101
118
|
if (!llm) {
|