@geminixiang/mikan 1.0.0-beta.67 → 1.0.0-beta.68
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/CHANGELOG.md +14 -0
- package/dist/adapters/slack/auto-reply-context.d.ts +7 -5
- package/dist/adapters/slack/auto-reply-context.d.ts.map +1 -1
- package/dist/adapters/slack/auto-reply-context.js +11 -53
- package/dist/adapters/slack/auto-reply-context.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +8 -0
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +65 -11
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/jev-context.d.ts +30 -0
- package/dist/adapters/slack/jev-context.d.ts.map +1 -0
- package/dist/adapters/slack/jev-context.js +67 -0
- package/dist/adapters/slack/jev-context.js.map +1 -0
- package/dist/adapters/slack/task-intent.d.ts +32 -0
- package/dist/adapters/slack/task-intent.d.ts.map +1 -0
- package/dist/adapters/slack/task-intent.js +72 -0
- package/dist/adapters/slack/task-intent.js.map +1 -0
- package/dist/adapters/slack/task-status.d.ts.map +1 -1
- package/dist/adapters/slack/task-status.js +6 -0
- package/dist/adapters/slack/task-status.js.map +1 -1
- package/dist/harness/index.d.ts +1 -1
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/jev.d.ts +26 -6
- package/dist/harness/jev.d.ts.map +1 -1
- package/dist/harness/jev.js +17 -3
- package/dist/harness/jev.js.map +1 -1
- package/dist/harness/presenter.d.ts.map +1 -1
- package/dist/harness/presenter.js +4 -3
- package/dist/harness/presenter.js.map +1 -1
- package/dist/harness/prompt.d.ts.map +1 -1
- package/dist/harness/prompt.js +1 -0
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/subagent-profiles.js +5 -5
- package/dist/harness/subagent-profiles.js.map +1 -1
- package/dist/harness/tools/index.d.ts.map +1 -1
- package/dist/harness/tools/index.js +3 -0
- package/dist/harness/tools/index.js.map +1 -1
- package/dist/harness/tools/jev.d.ts +21 -0
- package/dist/harness/tools/jev.d.ts.map +1 -0
- package/dist/harness/tools/jev.js +109 -0
- package/dist/harness/tools/jev.js.map +1 -0
- package/dist/sessions/session-store.d.ts +2 -0
- package/dist/sessions/session-store.d.ts.map +1 -1
- package/dist/sessions/session-store.js +1 -0
- package/dist/sessions/session-store.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface RecentLine {
|
|
2
|
+
ts: string;
|
|
3
|
+
speaker: string;
|
|
4
|
+
text: string;
|
|
5
|
+
isMikan: boolean;
|
|
6
|
+
}
|
|
7
|
+
/** Maps a Slack user id to a display name; undefined when unknown. */
|
|
8
|
+
export type SlackNameResolver = (userId: string) => string | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Rewrite native `<@U…>` mentions as `@Name` so Jev can tell "@someone else"
|
|
11
|
+
* from "@mikan" — the raw id carries no such signal. mikan's own id renders
|
|
12
|
+
* as `@mikan` regardless of its Slack profile name.
|
|
13
|
+
*/
|
|
14
|
+
export declare function humanizeMentions(text: string, resolve: SlackNameResolver, botUserId: string | null): string;
|
|
15
|
+
/**
|
|
16
|
+
* Recent messages from log.jsonl in the same scope as `event` — the channel's
|
|
17
|
+
* top level, or one thread (root included) — oldest first. Streamed bot
|
|
18
|
+
* responses are logged in chunks sharing one ts and are merged back into one
|
|
19
|
+
* line. Jev decisions score these alongside the new message, since a bare
|
|
20
|
+
* "好啊" or "好了嗎" cannot be judged on its own.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readRecentScope(conversationDir: string, event: {
|
|
23
|
+
ts: string;
|
|
24
|
+
thread_ts?: string;
|
|
25
|
+
}, options?: {
|
|
26
|
+
limit?: number;
|
|
27
|
+
humanize?: (text: string) => string;
|
|
28
|
+
}): RecentLine[];
|
|
29
|
+
export declare function formatRecentScope(lines: RecentLine[]): string;
|
|
30
|
+
//# sourceMappingURL=jev-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jev-context.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/jev-context.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,sEAAsE;AACtE,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAEvE;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,MAAM,CAMR;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,eAAe,EAAE,MAAM,EACvB,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EACzC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAAO,GACpE,UAAU,EAAE,CAmCd;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAE7D"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { isRecord, readTextFileIfExists } from "../../file-guards.js";
|
|
3
|
+
/**
|
|
4
|
+
* Rewrite native `<@U…>` mentions as `@Name` so Jev can tell "@someone else"
|
|
5
|
+
* from "@mikan" — the raw id carries no such signal. mikan's own id renders
|
|
6
|
+
* as `@mikan` regardless of its Slack profile name.
|
|
7
|
+
*/
|
|
8
|
+
export function humanizeMentions(text, resolve, botUserId) {
|
|
9
|
+
return text.replace(/<@([A-Z0-9]+)(?:\|[^>]*)?>/g, (_match, id) => {
|
|
10
|
+
if (botUserId && id === botUserId)
|
|
11
|
+
return "@mikan";
|
|
12
|
+
const name = resolve(id);
|
|
13
|
+
return name ? `@${name}` : `@${id}`;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Recent messages from log.jsonl in the same scope as `event` — the channel's
|
|
18
|
+
* top level, or one thread (root included) — oldest first. Streamed bot
|
|
19
|
+
* responses are logged in chunks sharing one ts and are merged back into one
|
|
20
|
+
* line. Jev decisions score these alongside the new message, since a bare
|
|
21
|
+
* "好啊" or "好了嗎" cannot be judged on its own.
|
|
22
|
+
*/
|
|
23
|
+
export function readRecentScope(conversationDir, event, options = {}) {
|
|
24
|
+
const limit = options.limit ?? 12;
|
|
25
|
+
const humanize = options.humanize ?? ((text) => text);
|
|
26
|
+
const raw = readTextFileIfExists(join(conversationDir, "log.jsonl"));
|
|
27
|
+
if (raw === undefined)
|
|
28
|
+
return [];
|
|
29
|
+
const lines = [];
|
|
30
|
+
for (const line of raw.split("\n")) {
|
|
31
|
+
if (!line)
|
|
32
|
+
continue;
|
|
33
|
+
let entry;
|
|
34
|
+
try {
|
|
35
|
+
entry = JSON.parse(line);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (!isRecord(entry) || typeof entry.ts !== "string" || typeof entry.text !== "string") {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const threadTs = typeof entry.threadTs === "string" ? entry.threadTs : undefined;
|
|
44
|
+
const inScope = event.thread_ts
|
|
45
|
+
? threadTs === event.thread_ts || entry.ts === event.thread_ts
|
|
46
|
+
: threadTs === undefined;
|
|
47
|
+
if (!inScope || entry.ts === event.ts)
|
|
48
|
+
continue;
|
|
49
|
+
const isMikan = entry.isMessagingBot === true && entry.user === "bot";
|
|
50
|
+
const speaker = isMikan
|
|
51
|
+
? "mikan"
|
|
52
|
+
: String(entry.displayName ?? entry.userName ?? entry.user ?? "unknown");
|
|
53
|
+
const previous = lines.at(-1);
|
|
54
|
+
if (previous && previous.isMikan && isMikan && previous.ts === entry.ts) {
|
|
55
|
+
previous.text += entry.text;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
lines.push({ ts: entry.ts, speaker, text: entry.text, isMikan });
|
|
59
|
+
}
|
|
60
|
+
for (const line of lines)
|
|
61
|
+
line.text = humanize(line.text);
|
|
62
|
+
return lines.slice(-limit);
|
|
63
|
+
}
|
|
64
|
+
export function formatRecentScope(lines) {
|
|
65
|
+
return lines.length ? lines.map((l) => `- ${l.speaker}: ${l.text}`).join("\n") : "(none)";
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=jev-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jev-context.js","sourceRoot":"","sources":["../../../src/adapters/slack/jev-context.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport { isRecord, readTextFileIfExists } from \"../../file-guards.js\";\n\nexport interface RecentLine {\n ts: string;\n speaker: string;\n text: string;\n isMikan: boolean;\n}\n\n/** Maps a Slack user id to a display name; undefined when unknown. */\nexport type SlackNameResolver = (userId: string) => string | undefined;\n\n/**\n * Rewrite native `<@U…>` mentions as `@Name` so Jev can tell \"@someone else\"\n * from \"@mikan\" — the raw id carries no such signal. mikan's own id renders\n * as `@mikan` regardless of its Slack profile name.\n */\nexport function humanizeMentions(\n text: string,\n resolve: SlackNameResolver,\n botUserId: string | null,\n): string {\n return text.replace(/<@([A-Z0-9]+)(?:\\|[^>]*)?>/g, (_match, id: string) => {\n if (botUserId && id === botUserId) return \"@mikan\";\n const name = resolve(id);\n return name ? `@${name}` : `@${id}`;\n });\n}\n\n/**\n * Recent messages from log.jsonl in the same scope as `event` — the channel's\n * top level, or one thread (root included) — oldest first. Streamed bot\n * responses are logged in chunks sharing one ts and are merged back into one\n * line. Jev decisions score these alongside the new message, since a bare\n * \"好啊\" or \"好了嗎\" cannot be judged on its own.\n */\nexport function readRecentScope(\n conversationDir: string,\n event: { ts: string; thread_ts?: string },\n options: { limit?: number; humanize?: (text: string) => string } = {},\n): RecentLine[] {\n const limit = options.limit ?? 12;\n const humanize = options.humanize ?? ((text: string) => text);\n const raw = readTextFileIfExists(join(conversationDir, \"log.jsonl\"));\n if (raw === undefined) return [];\n const lines: RecentLine[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (!line) continue;\n let entry: unknown;\n try {\n entry = JSON.parse(line);\n } catch {\n continue;\n }\n if (!isRecord(entry) || typeof entry.ts !== \"string\" || typeof entry.text !== \"string\") {\n continue;\n }\n const threadTs = typeof entry.threadTs === \"string\" ? entry.threadTs : undefined;\n const inScope = event.thread_ts\n ? threadTs === event.thread_ts || entry.ts === event.thread_ts\n : threadTs === undefined;\n if (!inScope || entry.ts === event.ts) continue;\n const isMikan = entry.isMessagingBot === true && entry.user === \"bot\";\n const speaker = isMikan\n ? \"mikan\"\n : String(entry.displayName ?? entry.userName ?? entry.user ?? \"unknown\");\n const previous = lines.at(-1);\n if (previous && previous.isMikan && isMikan && previous.ts === entry.ts) {\n previous.text += entry.text;\n continue;\n }\n lines.push({ ts: entry.ts, speaker, text: entry.text, isMikan });\n }\n for (const line of lines) line.text = humanize(line.text);\n return lines.slice(-limit);\n}\n\nexport function formatRecentScope(lines: RecentLine[]): string {\n return lines.length ? lines.map((l) => `- ${l.speaker}: ${l.text}`).join(\"\\n\") : \"(none)\";\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { TaskStatus } from "../../types.js";
|
|
2
|
+
import { type SlackNameResolver } from "./jev-context.js";
|
|
3
|
+
/**
|
|
4
|
+
* What a DM message means while a task is around:
|
|
5
|
+
* - `status`: a pure progress question, answered from observation without a model turn
|
|
6
|
+
* - `steer`: a supplement or correction for the running work, folded into its next step
|
|
7
|
+
* - `request`: anything else, handled as an ordinary conversation turn
|
|
8
|
+
*/
|
|
9
|
+
export type TaskIntent = "status" | "steer" | "request";
|
|
10
|
+
/** The shared `state` Jev scores: the scope's recent lines, the tasks in play, and the new message. */
|
|
11
|
+
export declare function buildTaskIntentState(conversationDir: string, event: {
|
|
12
|
+
ts: string;
|
|
13
|
+
thread_ts?: string;
|
|
14
|
+
user: string;
|
|
15
|
+
text: string;
|
|
16
|
+
}, options: {
|
|
17
|
+
speaker?: string;
|
|
18
|
+
tasks: TaskStatus[];
|
|
19
|
+
resolveName?: SlackNameResolver;
|
|
20
|
+
botUserId?: string | null;
|
|
21
|
+
}): string;
|
|
22
|
+
/**
|
|
23
|
+
* Classify with Jev. When Jev is unavailable or fails, reproduce the pre-Jev
|
|
24
|
+
* behavior exactly: the regex shortcut decides `status`, and other text is
|
|
25
|
+
* `steer` inside a task thread (where it always targeted that task) or
|
|
26
|
+
* `request` at top level.
|
|
27
|
+
*/
|
|
28
|
+
export declare function classifyTaskIntent(state: string, text: string, context: {
|
|
29
|
+
conversationId: string;
|
|
30
|
+
inTaskThread: boolean;
|
|
31
|
+
}): Promise<TaskIntent>;
|
|
32
|
+
//# sourceMappingURL=task-intent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-intent.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/task-intent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,kBAAkB,CAAC;AAG1B;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAWxD,uGAAuG;AACvG,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,MAAM,EACvB,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACrE,OAAO,EAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GACA,MAAM,CA0BR;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,GACzD,OAAO,CAAC,UAAU,CAAC,CAiCrB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { evaluateWithJev, JevNotConfiguredError } from "../../harness/index.js";
|
|
2
|
+
import { reportUserFacingError } from "../../observability/index.js";
|
|
3
|
+
import * as log from "../../log.js";
|
|
4
|
+
import { formatRecentScope, humanizeMentions, readRecentScope, } from "./jev-context.js";
|
|
5
|
+
import { isTaskStatusQuestion } from "./task-status.js";
|
|
6
|
+
const TASK_INTENT_CRITERIA = {
|
|
7
|
+
status: "Only asks whether the ongoing work is done, how it is going, what step it is on, or how long it will take. Contains no new instruction, constraint, correction, or request for content.",
|
|
8
|
+
steer: "Adds information, a constraint, a correction, or a change of direction for the ongoing work while it continues (e.g. 先不要部署, also check the staging config, use the other branch). May be combined with a progress question.",
|
|
9
|
+
request: "A new standalone question or request unrelated to steering the ongoing work, a reaction to a finished result, or anything else.",
|
|
10
|
+
};
|
|
11
|
+
/** The shared `state` Jev scores: the scope's recent lines, the tasks in play, and the new message. */
|
|
12
|
+
export function buildTaskIntentState(conversationDir, event, options) {
|
|
13
|
+
const resolve = options.resolveName ?? (() => undefined);
|
|
14
|
+
const humanize = (text) => humanizeMentions(text, resolve, options.botUserId ?? null);
|
|
15
|
+
const recent = readRecentScope(conversationDir, event, { humanize });
|
|
16
|
+
const tasks = options.tasks.length
|
|
17
|
+
? options.tasks
|
|
18
|
+
.map((t) => `- ${t.status}${t.currentTool ? ` (currently: ${t.currentTool})` : ""}: ${t.acknowledgement}`)
|
|
19
|
+
.join("\n")
|
|
20
|
+
: "(none)";
|
|
21
|
+
return [
|
|
22
|
+
event.thread_ts
|
|
23
|
+
? "Slack DM reply inside a background task thread."
|
|
24
|
+
: "Slack DM top-level message while background tasks exist.",
|
|
25
|
+
"",
|
|
26
|
+
"Tasks in this DM (most recent first):",
|
|
27
|
+
tasks,
|
|
28
|
+
"",
|
|
29
|
+
"Recent messages in this scope (oldest first):",
|
|
30
|
+
formatRecentScope(recent),
|
|
31
|
+
"",
|
|
32
|
+
`NEW message from ${options.speaker ?? event.user}:`,
|
|
33
|
+
humanize(event.text),
|
|
34
|
+
].join("\n");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Classify with Jev. When Jev is unavailable or fails, reproduce the pre-Jev
|
|
38
|
+
* behavior exactly: the regex shortcut decides `status`, and other text is
|
|
39
|
+
* `steer` inside a task thread (where it always targeted that task) or
|
|
40
|
+
* `request` at top level.
|
|
41
|
+
*/
|
|
42
|
+
export async function classifyTaskIntent(state, text, context) {
|
|
43
|
+
const fallback = () => isTaskStatusQuestion(text) ? "status" : context.inTaskThread ? "steer" : "request";
|
|
44
|
+
try {
|
|
45
|
+
const result = await evaluateWithJev(state, {
|
|
46
|
+
intent: {
|
|
47
|
+
type: "choice",
|
|
48
|
+
instructions: "Given the tasks in play and the recent conversation, what does the NEW message mean?",
|
|
49
|
+
criteria: TASK_INTENT_CRITERIA,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
const choice = result.answers.intent.choice;
|
|
53
|
+
const probabilities = result.answers.intent.probabilities;
|
|
54
|
+
log.logInfo(`[${context.conversationId}] jev task intent: ${choice}${probabilities ? ` ${JSON.stringify(probabilities)}` : ""} text="${text.slice(0, 80)}"`);
|
|
55
|
+
if (choice === "status" || choice === "steer" || choice === "request")
|
|
56
|
+
return choice;
|
|
57
|
+
return fallback();
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
if (!(err instanceof JevNotConfiguredError)) {
|
|
61
|
+
reportUserFacingError(err, {
|
|
62
|
+
domain: "chat_platform",
|
|
63
|
+
surface: "slack_task_intent_jev",
|
|
64
|
+
operation: "evaluate",
|
|
65
|
+
severity: "warning",
|
|
66
|
+
context: { conversationId: context.conversationId },
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return fallback();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=task-intent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-intent.js","sourceRoot":"","sources":["../../../src/adapters/slack/task-intent.ts"],"names":[],"mappings":"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","sourcesContent":["import { evaluateWithJev, JevNotConfiguredError } from \"../../harness/index.js\";\nimport { reportUserFacingError } from \"../../observability/index.js\";\nimport * as log from \"../../log.js\";\nimport type { TaskStatus } from \"../../types.js\";\nimport {\n formatRecentScope,\n humanizeMentions,\n readRecentScope,\n type SlackNameResolver,\n} from \"./jev-context.js\";\nimport { isTaskStatusQuestion } from \"./task-status.js\";\n\n/**\n * What a DM message means while a task is around:\n * - `status`: a pure progress question, answered from observation without a model turn\n * - `steer`: a supplement or correction for the running work, folded into its next step\n * - `request`: anything else, handled as an ordinary conversation turn\n */\nexport type TaskIntent = \"status\" | \"steer\" | \"request\";\n\nconst TASK_INTENT_CRITERIA = {\n status:\n \"Only asks whether the ongoing work is done, how it is going, what step it is on, or how long it will take. Contains no new instruction, constraint, correction, or request for content.\",\n steer:\n \"Adds information, a constraint, a correction, or a change of direction for the ongoing work while it continues (e.g. 先不要部署, also check the staging config, use the other branch). May be combined with a progress question.\",\n request:\n \"A new standalone question or request unrelated to steering the ongoing work, a reaction to a finished result, or anything else.\",\n} as const;\n\n/** The shared `state` Jev scores: the scope's recent lines, the tasks in play, and the new message. */\nexport function buildTaskIntentState(\n conversationDir: string,\n event: { ts: string; thread_ts?: string; user: string; text: string },\n options: {\n speaker?: string;\n tasks: TaskStatus[];\n resolveName?: SlackNameResolver;\n botUserId?: string | null;\n },\n): string {\n const resolve = options.resolveName ?? (() => undefined);\n const humanize = (text: string) => humanizeMentions(text, resolve, options.botUserId ?? null);\n const recent = readRecentScope(conversationDir, event, { humanize });\n const tasks = options.tasks.length\n ? options.tasks\n .map(\n (t) =>\n `- ${t.status}${t.currentTool ? ` (currently: ${t.currentTool})` : \"\"}: ${t.acknowledgement}`,\n )\n .join(\"\\n\")\n : \"(none)\";\n return [\n event.thread_ts\n ? \"Slack DM reply inside a background task thread.\"\n : \"Slack DM top-level message while background tasks exist.\",\n \"\",\n \"Tasks in this DM (most recent first):\",\n tasks,\n \"\",\n \"Recent messages in this scope (oldest first):\",\n formatRecentScope(recent),\n \"\",\n `NEW message from ${options.speaker ?? event.user}:`,\n humanize(event.text),\n ].join(\"\\n\");\n}\n\n/**\n * Classify with Jev. When Jev is unavailable or fails, reproduce the pre-Jev\n * behavior exactly: the regex shortcut decides `status`, and other text is\n * `steer` inside a task thread (where it always targeted that task) or\n * `request` at top level.\n */\nexport async function classifyTaskIntent(\n state: string,\n text: string,\n context: { conversationId: string; inTaskThread: boolean },\n): Promise<TaskIntent> {\n const fallback = (): TaskIntent =>\n isTaskStatusQuestion(text) ? \"status\" : context.inTaskThread ? \"steer\" : \"request\";\n try {\n const result = await evaluateWithJev(state, {\n intent: {\n type: \"choice\",\n instructions:\n \"Given the tasks in play and the recent conversation, what does the NEW message mean?\",\n criteria: TASK_INTENT_CRITERIA,\n },\n });\n const choice = result.answers.intent.choice;\n const probabilities = result.answers.intent.probabilities;\n log.logInfo(\n `[${context.conversationId}] jev task intent: ${choice}${\n probabilities ? ` ${JSON.stringify(probabilities)}` : \"\"\n } text=\"${text.slice(0, 80)}\"`,\n );\n if (choice === \"status\" || choice === \"steer\" || choice === \"request\") return choice;\n return fallback();\n } catch (err) {\n if (!(err instanceof JevNotConfiguredError)) {\n reportUserFacingError(err, {\n domain: \"chat_platform\",\n surface: \"slack_task_intent_jev\",\n operation: \"evaluate\",\n severity: \"warning\",\n context: { conversationId: context.conversationId },\n });\n }\n return fallback();\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-status.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/task-status.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEjE,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAI1D;AAED,wBAAgB,aAAa,CAAC,eAAe,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAa1E;AAED,wBAAsB,eAAe,CACnC,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,cAAc,EAAE,EACzB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"task-status.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/task-status.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEjE,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAI1D;AAED,wBAAgB,aAAa,CAAC,eAAe,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAa1E;AAED,wBAAsB,eAAe,CACnC,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,cAAc,EAAE,EACzB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,EAAE,CAAC,CAwDvB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAwB5D"}
|
|
@@ -56,6 +56,12 @@ export async function querySlackTasks(conversationDir, channel, running, session
|
|
|
56
56
|
observation.status = state.result.status;
|
|
57
57
|
observation.endedAt = new Date(state.result.endedAt).toISOString();
|
|
58
58
|
}
|
|
59
|
+
else if (!state.started) {
|
|
60
|
+
// Admitted (the root exists) but no operation has been recorded yet:
|
|
61
|
+
// the run is still waiting in the queue. An open operation with no
|
|
62
|
+
// runtime stays unknown, since that is a crash, not a queue.
|
|
63
|
+
observation.status = "queued";
|
|
64
|
+
}
|
|
59
65
|
}
|
|
60
66
|
catch (error) {
|
|
61
67
|
reportUserFacingError(error, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-status.js","sourceRoot":"","sources":["../../../src/adapters/slack/task-status.ts"],"names":[],"mappings":"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","sourcesContent":["import { readTextFileIfExists } from \"../../file-guards.js\";\nimport { join } from \"node:path\";\nimport { resolveSlackSessionKey } from \"./session.js\";\nimport { getThreadSessionFile } from \"../../sessions/store.js\";\nimport { reportUserFacingError } from \"../../observability/index.js\";\nimport { SessionStore } from \"../../sessions/session-store.js\";\nimport type { TaskStatus, RunningSession } from \"../../types.js\";\n\n/** Narrow pure-status shortcut. Mixed instructions must still reach the agent. */\nexport function isTaskStatusQuestion(text: string): boolean {\n return /^(好了嗎|完成了嗎|有進展嗎|現在做到哪了|進度如何|還要多久|還要多久啊|現在怎麼樣|怎麼樣了|how(?:'s| is) it going|are you done|any updates|status)[??!!。\\s]*$/i.test(\n text.trim(),\n );\n}\n\nexport function readTaskRoots(conversationDir: string): Map<string, string> {\n const raw = readTextFileIfExists(join(conversationDir, \"log.jsonl\")) ?? \"\";\n const roots = new Map<string, string>();\n for (const line of raw.split(\"\\n\")) {\n try {\n const entry = JSON.parse(line);\n if (entry.taskRoot === true && entry.isMessagingBot === true && typeof entry.ts === \"string\")\n roots.set(entry.ts, String(entry.text ?? \"\"));\n } catch {\n /* unrelated malformed log record */\n }\n }\n return roots;\n}\n\nexport async function querySlackTasks(\n conversationDir: string,\n channel: string,\n running: RunningSession[],\n sessionKey?: string,\n): Promise<TaskStatus[]> {\n const roots = readTaskRoots(conversationDir);\n const matching = [...roots]\n .toReversed()\n .filter(([root]) => !sessionKey || resolveSlackSessionKey(channel, root) === sessionKey);\n const activeByKey = new Map(\n running\n .filter((s) => s.address.platform === \"slack\" && s.address.conversationId === channel)\n .map((s) => [s.sessionKey, s]),\n );\n // Never hide active work behind the recent-completed history limit.\n const selected = matching.filter(\n ([root], index) => index < 10 || activeByKey.has(resolveSlackSessionKey(channel, root)),\n );\n const observations: TaskStatus[] = [];\n for (const [root, acknowledgement] of selected) {\n const key = resolveSlackSessionKey(channel, root);\n const active = activeByKey.get(key);\n const observation: TaskStatus = {\n sessionKey: key,\n threadTs: root,\n acknowledgement,\n observedAt: new Date().toISOString(),\n status: \"unknown\",\n };\n if (active) {\n observation.status = active.stopping ? \"stopping\" : \"running\";\n observation.currentTool = active.currentTool;\n observations.push(observation);\n continue;\n }\n try {\n const state = await SessionStore.inspectExecution(getThreadSessionFile(conversationDir, key));\n if (!state.open && state.result) {\n observation.status = state.result.status;\n observation.endedAt = new Date(state.result.endedAt).toISOString();\n }\n } catch (error) {\n reportUserFacingError(error, {\n domain: \"mikan\",\n surface: \"task_status\",\n operation: \"inspect_task_status\",\n severity: \"warning\",\n platform: \"slack\",\n context: { conversationId: channel, sessionKey: key, threadTs: root },\n });\n // No runtime or durable outcome: do not invent queued/completed state.\n }\n observations.push(observation);\n }\n return observations;\n}\n\nexport function formatTaskStatus(tasks: TaskStatus[]): string {\n if (!tasks.length) return \"找不到這個任務的狀態。\";\n return tasks\n .map((task) => {\n switch (task.status) {\n case \"running\":\n return `還在處理${task.currentTool ? `,目前正在:${task.currentTool}` : \"\"}。目前無法可靠估計還要多久,結束後會通知你。`;\n case \"completed\":\n return \"這一輪執行已結束。這是執行狀態,不代表結果訊息已成功送達;請查看任務對話串。\";\n case \"aborted\":\n return \"這一輪已停止,不會自行繼續。你可以補充新要求後再繼續。\";\n case \"failed\":\n return \"這一輪執行失敗。\";\n case \"queued\":\n return \"任務尚未開始執行。\";\n case \"declined\":\n return \"這一輪沒有執行。\";\n case \"stopping\":\n return \"正在停止,還在等待執行收尾。\";\n default:\n return \"目前無法確認任務狀態,不能判定已完成。\";\n }\n })\n .join(\"\\n\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"task-status.js","sourceRoot":"","sources":["../../../src/adapters/slack/task-status.ts"],"names":[],"mappings":"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","sourcesContent":["import { readTextFileIfExists } from \"../../file-guards.js\";\nimport { join } from \"node:path\";\nimport { resolveSlackSessionKey } from \"./session.js\";\nimport { getThreadSessionFile } from \"../../sessions/store.js\";\nimport { reportUserFacingError } from \"../../observability/index.js\";\nimport { SessionStore } from \"../../sessions/session-store.js\";\nimport type { TaskStatus, RunningSession } from \"../../types.js\";\n\n/** Narrow pure-status shortcut. Mixed instructions must still reach the agent. */\nexport function isTaskStatusQuestion(text: string): boolean {\n return /^(好了嗎|完成了嗎|有進展嗎|現在做到哪了|進度如何|還要多久|還要多久啊|現在怎麼樣|怎麼樣了|how(?:'s| is) it going|are you done|any updates|status)[??!!。\\s]*$/i.test(\n text.trim(),\n );\n}\n\nexport function readTaskRoots(conversationDir: string): Map<string, string> {\n const raw = readTextFileIfExists(join(conversationDir, \"log.jsonl\")) ?? \"\";\n const roots = new Map<string, string>();\n for (const line of raw.split(\"\\n\")) {\n try {\n const entry = JSON.parse(line);\n if (entry.taskRoot === true && entry.isMessagingBot === true && typeof entry.ts === \"string\")\n roots.set(entry.ts, String(entry.text ?? \"\"));\n } catch {\n /* unrelated malformed log record */\n }\n }\n return roots;\n}\n\nexport async function querySlackTasks(\n conversationDir: string,\n channel: string,\n running: RunningSession[],\n sessionKey?: string,\n): Promise<TaskStatus[]> {\n const roots = readTaskRoots(conversationDir);\n const matching = [...roots]\n .toReversed()\n .filter(([root]) => !sessionKey || resolveSlackSessionKey(channel, root) === sessionKey);\n const activeByKey = new Map(\n running\n .filter((s) => s.address.platform === \"slack\" && s.address.conversationId === channel)\n .map((s) => [s.sessionKey, s]),\n );\n // Never hide active work behind the recent-completed history limit.\n const selected = matching.filter(\n ([root], index) => index < 10 || activeByKey.has(resolveSlackSessionKey(channel, root)),\n );\n const observations: TaskStatus[] = [];\n for (const [root, acknowledgement] of selected) {\n const key = resolveSlackSessionKey(channel, root);\n const active = activeByKey.get(key);\n const observation: TaskStatus = {\n sessionKey: key,\n threadTs: root,\n acknowledgement,\n observedAt: new Date().toISOString(),\n status: \"unknown\",\n };\n if (active) {\n observation.status = active.stopping ? \"stopping\" : \"running\";\n observation.currentTool = active.currentTool;\n observations.push(observation);\n continue;\n }\n try {\n const state = await SessionStore.inspectExecution(getThreadSessionFile(conversationDir, key));\n if (!state.open && state.result) {\n observation.status = state.result.status;\n observation.endedAt = new Date(state.result.endedAt).toISOString();\n } else if (!state.started) {\n // Admitted (the root exists) but no operation has been recorded yet:\n // the run is still waiting in the queue. An open operation with no\n // runtime stays unknown, since that is a crash, not a queue.\n observation.status = \"queued\";\n }\n } catch (error) {\n reportUserFacingError(error, {\n domain: \"mikan\",\n surface: \"task_status\",\n operation: \"inspect_task_status\",\n severity: \"warning\",\n platform: \"slack\",\n context: { conversationId: channel, sessionKey: key, threadTs: root },\n });\n // No runtime or durable outcome: do not invent queued/completed state.\n }\n observations.push(observation);\n }\n return observations;\n}\n\nexport function formatTaskStatus(tasks: TaskStatus[]): string {\n if (!tasks.length) return \"找不到這個任務的狀態。\";\n return tasks\n .map((task) => {\n switch (task.status) {\n case \"running\":\n return `還在處理${task.currentTool ? `,目前正在:${task.currentTool}` : \"\"}。目前無法可靠估計還要多久,結束後會通知你。`;\n case \"completed\":\n return \"這一輪執行已結束。這是執行狀態,不代表結果訊息已成功送達;請查看任務對話串。\";\n case \"aborted\":\n return \"這一輪已停止,不會自行繼續。你可以補充新要求後再繼續。\";\n case \"failed\":\n return \"這一輪執行失敗。\";\n case \"queued\":\n return \"任務尚未開始執行。\";\n case \"declined\":\n return \"這一輪沒有執行。\";\n case \"stopping\":\n return \"正在停止,還在等待執行收尾。\";\n default:\n return \"目前無法確認任務狀態,不能判定已完成。\";\n }\n })\n .join(\"\\n\\n\");\n}\n"]}
|
package/dist/harness/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
export { DEFAULT_HTTP_IDLE_TIMEOUT_MS, configureHttpDispatcher, parseHttpIdleTimeoutMs, } from "./http.js";
|
|
9
9
|
export { MikanModels, defaultModelsJsonPath } from "./models.js";
|
|
10
10
|
export type { CreateMikanModelsOptions } from "./types.js";
|
|
11
|
-
export { JEV_MODEL_ID, JevNotConfiguredError, JevRequestError, evaluateWithJev, type EvaluateWithJevOptions, type JevAnswer, type JevQuestion, type JevQuestions, type JevResult, } from "./jev.js";
|
|
11
|
+
export { JEV_MODEL_ID, JevNotConfiguredError, JevRequestError, evaluateWithJev, type EvaluateWithJevOptions, type JevAnswer, type JevEntry, type JevQuestion, type JevQuestions, type JevResult, } from "./jev.js";
|
|
12
12
|
export { SessionStore } from "../sessions/session-store.js";
|
|
13
13
|
export type { SessionContext, SessionEntry, SessionHeader, SessionMessageEntry, } from "../sessions/types.js";
|
|
14
14
|
export { CURRENT_SESSION_VERSION } from "../sessions/types.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,YAAY,EACZ,aAAa,EACb,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACzF,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,YAAY,EACZ,aAAa,EACb,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACzF,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,GAOhB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAO5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAOjD,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,GAEvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAcN,MAAM,YAAY,CAAC","sourcesContent":["/**\n * mikan agent harness.\n *\n * Application integration of pi-agent-core's native AgentHarness (durable\n * operations, tools, retries, compaction, recovery) and pi-ai (providers,\n * models, auth). See `src/harness/README.md` for the architecture.\n */\nexport {\n DEFAULT_HTTP_IDLE_TIMEOUT_MS,\n configureHttpDispatcher,\n parseHttpIdleTimeoutMs,\n} from \"./http.js\";\nexport { MikanModels, defaultModelsJsonPath } from \"./models.js\";\nexport type { CreateMikanModelsOptions } from \"./types.js\";\nexport {\n JEV_MODEL_ID,\n JevNotConfiguredError,\n JevRequestError,\n evaluateWithJev,\n type EvaluateWithJevOptions,\n type JevAnswer,\n type JevEntry,\n type JevQuestion,\n type JevQuestions,\n type JevResult,\n} from \"./jev.js\";\nexport { SessionStore } from \"../sessions/session-store.js\";\nexport type {\n SessionContext,\n SessionEntry,\n SessionHeader,\n SessionMessageEntry,\n} from \"../sessions/types.js\";\nexport { CURRENT_SESSION_VERSION } from \"../sessions/types.js\";\nexport { MikanAgentSession } from \"./session.js\";\nexport type {\n CompactionReason,\n HarnessEvent,\n HarnessEventListener,\n MikanAgentSessionOptions,\n} from \"./types.js\";\nexport { formatSkillsForPrompt, loadSkillsFromDir, parseFrontmatter } from \"./skills.js\";\nexport type { LoadSkillsResult, MikanSkill, SkillDiagnostic } from \"./types.js\";\nexport { loadSubagentProfiles } from \"./subagent-profiles.js\";\nexport type { LoadSubagentProfilesResult, SubagentProfileDiagnostic } from \"./types.js\";\nexport {\n DEFAULT_BUDGET_SETTINGS,\n DEFAULT_EVENT_BUDGET,\n DEFAULT_RETRY_SETTINGS,\n resolveHarnessSettings,\n type CompactionSettings,\n} from \"./session.js\";\nexport type { BudgetSettings, HarnessSettings, RetrySettings } from \"./types.js\";\nexport {\n type SubagentModelSpec,\n type SubagentProfile,\n type SubagentParentContext,\n type SubagentRunBudget,\n type SubagentRunOutput,\n type SubagentRunRequest,\n type SubagentRunResult,\n type SubagentRunStatus,\n type SubagentUsage,\n type SubagentUsageSink,\n type BranchSummaryEntry,\n type CompactionEntry,\n type CustomEntry,\n} from \"./types.js\";\n"]}
|
package/dist/harness/jev.d.ts
CHANGED
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
/** The current public Jev model id on OpenRouter. */
|
|
2
2
|
export declare const JEV_MODEL_ID = "~typesafe/jev-latest";
|
|
3
|
+
/**
|
|
4
|
+
* Any value Jev accepts as text-bearing structure: a string, a JSON object,
|
|
5
|
+
* an array, or `null`. State, instructions, and criteria descriptions all
|
|
6
|
+
* take this shape; Jev is trained to read the structure, so objects with
|
|
7
|
+
* labelled keys are preferred over string templates.
|
|
8
|
+
*/
|
|
9
|
+
export type JevEntry = string | number | boolean | null | JevEntry[] | {
|
|
10
|
+
[key: string]: JevEntry;
|
|
11
|
+
};
|
|
3
12
|
/** A shared caller-facing question shape; translated to OpenRouter's wire format below. */
|
|
4
13
|
export type JevQuestion = {
|
|
5
14
|
type: "boolean";
|
|
6
|
-
instructions:
|
|
15
|
+
instructions: JevEntry;
|
|
16
|
+
/** Optional descriptions of the yes / no outcomes. */
|
|
17
|
+
criteria?: {
|
|
18
|
+
true?: JevEntry;
|
|
19
|
+
false?: JevEntry;
|
|
20
|
+
};
|
|
7
21
|
} | {
|
|
8
22
|
type: "choice";
|
|
9
|
-
instructions:
|
|
10
|
-
criteria: Record<string,
|
|
23
|
+
instructions: JevEntry;
|
|
24
|
+
criteria: Record<string, JevEntry>;
|
|
11
25
|
} | {
|
|
12
26
|
type: "score";
|
|
13
|
-
instructions:
|
|
14
|
-
criteria: readonly
|
|
27
|
+
instructions: JevEntry;
|
|
28
|
+
criteria: readonly JevEntry[];
|
|
15
29
|
};
|
|
16
30
|
export type JevQuestions = Record<string, JevQuestion>;
|
|
17
31
|
export type JevAnswer<QUESTION extends JevQuestion> = QUESTION extends {
|
|
@@ -20,12 +34,18 @@ export type JevAnswer<QUESTION extends JevQuestion> = QUESTION extends {
|
|
|
20
34
|
type: "choice";
|
|
21
35
|
choice: string;
|
|
22
36
|
probabilities?: Record<string, number>;
|
|
37
|
+
/** 0-1 statistic over `probabilities`; low means no option clearly fits. */
|
|
38
|
+
confidence?: number;
|
|
23
39
|
} : QUESTION extends {
|
|
24
40
|
type: "score";
|
|
25
41
|
} ? {
|
|
26
42
|
type: "score";
|
|
43
|
+
/** Expected level index; fractional between levels. */
|
|
27
44
|
score: number;
|
|
28
45
|
probabilities?: Record<string, number>;
|
|
46
|
+
/** Level index -> criterion text, as echoed by Jev. */
|
|
47
|
+
legend?: Record<string, string>;
|
|
48
|
+
confidence?: number;
|
|
29
49
|
} : {
|
|
30
50
|
type: "boolean";
|
|
31
51
|
probability: number;
|
|
@@ -61,5 +81,5 @@ export interface EvaluateWithJevOptions {
|
|
|
61
81
|
* questions here is cheap (they share the input) and is preferred over
|
|
62
82
|
* separate calls per question.
|
|
63
83
|
*/
|
|
64
|
-
export declare function evaluateWithJev<const QUESTIONS extends JevQuestions>(state:
|
|
84
|
+
export declare function evaluateWithJev<const QUESTIONS extends JevQuestions>(state: JevEntry, questions: QUESTIONS, options?: EvaluateWithJevOptions): Promise<JevResult<QUESTIONS>>;
|
|
65
85
|
//# sourceMappingURL=jev.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jev.d.ts","sourceRoot":"","sources":["../../src/harness/jev.ts"],"names":[],"mappings":"AAwBA,qDAAqD;AACrD,eAAO,MAAM,YAAY,yBAAyB,CAAC;AAInD,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GACnB;
|
|
1
|
+
{"version":3,"file":"jev.d.ts","sourceRoot":"","sources":["../../src/harness/jev.ts"],"names":[],"mappings":"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"}
|
package/dist/harness/jev.js
CHANGED
|
@@ -42,7 +42,10 @@ function toOpenRouterQuestion(question) {
|
|
|
42
42
|
return {
|
|
43
43
|
type: "noul",
|
|
44
44
|
instructions: question.instructions,
|
|
45
|
-
criteria: {
|
|
45
|
+
criteria: {
|
|
46
|
+
true: question.criteria?.true ?? "Yes",
|
|
47
|
+
false: question.criteria?.false ?? "No",
|
|
48
|
+
},
|
|
46
49
|
};
|
|
47
50
|
}
|
|
48
51
|
return question;
|
|
@@ -52,9 +55,20 @@ function fromOpenRouterAnswer(answer) {
|
|
|
52
55
|
return { type: "boolean", probability: answer.noul ?? 0 };
|
|
53
56
|
}
|
|
54
57
|
if (answer.type === "choice") {
|
|
55
|
-
return {
|
|
58
|
+
return {
|
|
59
|
+
type: "choice",
|
|
60
|
+
choice: answer.choice ?? "",
|
|
61
|
+
probabilities: answer.probabilities,
|
|
62
|
+
confidence: answer.confidence,
|
|
63
|
+
};
|
|
56
64
|
}
|
|
57
|
-
return {
|
|
65
|
+
return {
|
|
66
|
+
type: "score",
|
|
67
|
+
score: answer.score ?? 0,
|
|
68
|
+
probabilities: answer.probabilities,
|
|
69
|
+
legend: answer.legend,
|
|
70
|
+
confidence: answer.confidence,
|
|
71
|
+
};
|
|
58
72
|
}
|
|
59
73
|
/**
|
|
60
74
|
* Evaluate one or more typed questions against a shared `state` using Jev,
|
package/dist/harness/jev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jev.js","sourceRoot":"","sources":["../../src/harness/jev.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Jev (typesafe/jev) client, reached through OpenRouter's decisions API.\n *\n * Jev is a \"System One\" evaluation model: it scores a shared `state`\n * against typed questions (a yes/no probability, a multiple choice, or a\n * position on an ordered scale) and returns calibrated probabilities. It\n * does not generate text or tool calls, so it cannot be driven through\n * pi-ai's `Provider`/`Model`/`stream()` contract the way every model\n * `models.ts` catalogs is — that contract is chat/completion shaped\n * (system prompt + messages in, streamed text/tool-call events out), and\n * Jev's typed-decision shape does not fit it. Jev is therefore not a\n * selectable chat provider: callers import `evaluateWithJev` directly at\n * whatever call site wants a fast, cheap, type-safe decision (e.g.\n * classification, routing, guardrails), and interpret the returned\n * probabilities themselves.\n *\n * Requires `OPENROUTER_API_KEY` (see env-manifest.ts) — the same key\n * pi-ai's `openrouter` chat provider reads. `evaluateWithJev` calls\n * OpenRouter's `/api/alpha/decisions` REST endpoint directly; this is a\n * plain typed-decision API, not chat/completion, so it does not go\n * through pi-ai's provider machinery.\n */\nimport { readEnv } from \"../env-manifest.js\";\n\n/** The current public Jev model id on OpenRouter. */\nexport const JEV_MODEL_ID = \"~typesafe/jev-latest\";\n\nconst OPENROUTER_DECISIONS_URL = \"https://openrouter.ai/api/alpha/decisions\";\n\n/** A shared caller-facing question shape; translated to OpenRouter's wire format below. */\nexport type JevQuestion =\n | { type: \"boolean\"; instructions: string }\n | { type: \"choice\"; instructions: string; criteria: Record<string, string> }\n | { type: \"score\"; instructions: string; criteria: readonly string[] };\n\nexport type JevQuestions = Record<string, JevQuestion>;\n\nexport type JevAnswer<QUESTION extends JevQuestion> = QUESTION extends { type: \"choice\" }\n ? {\n type: \"choice\";\n choice: string;\n probabilities?: Record<string, number>;\n }\n : QUESTION extends { type: \"score\" }\n ? { type: \"score\"; score: number; probabilities?: Record<string, number> }\n : { type: \"boolean\"; probability: number };\n\nexport interface JevResult<QUESTIONS extends JevQuestions> {\n readonly answers: { [ID in keyof QUESTIONS]: JevAnswer<QUESTIONS[ID]> };\n readonly usage: {\n inputTokens: number | undefined;\n outputTokens: number | undefined;\n cost: number | undefined;\n };\n readonly model: string;\n}\n\nexport class JevNotConfiguredError extends Error {\n constructor() {\n super(\n \"Jev requires OPENROUTER_API_KEY (an OpenRouter API key). Set it in the environment before calling evaluateWithJev().\",\n );\n this.name = \"JevNotConfiguredError\";\n }\n}\n\nexport class JevRequestError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n ) {\n super(message);\n this.name = \"JevRequestError\";\n }\n}\n\nexport interface EvaluateWithJevOptions {\n /** Evaluation model id; defaults to the current public Jev model. */\n model?: string;\n abortSignal?: AbortSignal;\n headers?: Record<string, string>;\n}\n\n// ── wire format (OpenRouter decisions API) ──────────────────────────────────\n\ntype OpenRouterQuestion =\n | { type: \"noul\"; instructions: string; criteria: { true: string; false: string } }\n | { type: \"choice\"; instructions: string; criteria: Record<string, string> }\n | { type: \"score\"; instructions: string; criteria: readonly string[] };\n\ninterface OpenRouterAnswer {\n type: \"noul\" | \"choice\" | \"score\";\n noul?: number;\n choice?: string;\n score?: number;\n probabilities?: Record<string, number>;\n}\n\ninterface OpenRouterDecisionsResponse {\n model: string;\n answers: Record<string, OpenRouterAnswer>;\n usage?: { input_tokens?: number; output_tokens?: number; cost?: number };\n error?: { message: string; code?: number };\n}\n\nfunction toOpenRouterQuestion(question: JevQuestion): OpenRouterQuestion {\n if (question.type === \"boolean\") {\n return {\n type: \"noul\",\n instructions: question.instructions,\n criteria: { true: \"Yes\", false: \"No\" },\n };\n }\n return question;\n}\n\nfunction fromOpenRouterAnswer(answer: OpenRouterAnswer): JevAnswer<JevQuestion> {\n if (answer.type === \"noul\") {\n return { type: \"boolean\", probability: answer.noul ?? 0 };\n }\n if (answer.type === \"choice\") {\n return { type: \"choice\", choice: answer.choice ?? \"\", probabilities: answer.probabilities };\n }\n return { type: \"score\", score: answer.score ?? 0, probabilities: answer.probabilities };\n}\n\n/**\n * Evaluate one or more typed questions against a shared `state` using Jev,\n * reached through OpenRouter's decisions API. Every question is scored\n * independently against the same state in a single request; batching\n * questions here is cheap (they share the input) and is preferred over\n * separate calls per question.\n */\nexport async function evaluateWithJev<const QUESTIONS extends JevQuestions>(\n state: string,\n questions: QUESTIONS,\n options: EvaluateWithJevOptions = {},\n): Promise<JevResult<QUESTIONS>> {\n const apiKey = readEnv(\"OPENROUTER_API_KEY\");\n if (!apiKey) throw new JevNotConfiguredError();\n\n const wireQuestions: Record<string, OpenRouterQuestion> = {};\n for (const [id, question] of Object.entries(questions)) {\n wireQuestions[id] = toOpenRouterQuestion(question);\n }\n\n const response = await fetch(OPENROUTER_DECISIONS_URL, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n body: JSON.stringify({\n model: options.model ?? JEV_MODEL_ID,\n state,\n questions: wireQuestions,\n }),\n signal: options.abortSignal,\n });\n\n const body = (await response.json()) as OpenRouterDecisionsResponse;\n if (!response.ok || body.error) {\n throw new JevRequestError(\n body.error?.message ?? `Jev request failed with status ${response.status}`,\n body.error?.code ?? response.status,\n );\n }\n\n const answers = {} as { [ID in keyof QUESTIONS]: JevAnswer<QUESTIONS[ID]> };\n for (const id of Object.keys(questions)) {\n const answer = body.answers[id];\n if (!answer) throw new JevRequestError(`Jev response missing answer for \"${id}\"`, 502);\n (answers as Record<string, JevAnswer<JevQuestion>>)[id] = fromOpenRouterAnswer(answer);\n }\n\n return {\n answers,\n usage: {\n inputTokens: body.usage?.input_tokens,\n outputTokens: body.usage?.output_tokens,\n cost: body.usage?.cost,\n },\n model: body.model,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"jev.js","sourceRoot":"","sources":["../../src/harness/jev.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Jev (typesafe/jev) client, reached through OpenRouter's decisions API.\n *\n * Jev is a \"System One\" evaluation model: it scores a shared `state`\n * against typed questions (a yes/no probability, a multiple choice, or a\n * position on an ordered scale) and returns calibrated probabilities. It\n * does not generate text or tool calls, so it cannot be driven through\n * pi-ai's `Provider`/`Model`/`stream()` contract the way every model\n * `models.ts` catalogs is — that contract is chat/completion shaped\n * (system prompt + messages in, streamed text/tool-call events out), and\n * Jev's typed-decision shape does not fit it. Jev is therefore not a\n * selectable chat provider: callers import `evaluateWithJev` directly at\n * whatever call site wants a fast, cheap, type-safe decision (e.g.\n * classification, routing, guardrails), and interpret the returned\n * probabilities themselves.\n *\n * Requires `OPENROUTER_API_KEY` (see env-manifest.ts) — the same key\n * pi-ai's `openrouter` chat provider reads. `evaluateWithJev` calls\n * OpenRouter's `/api/alpha/decisions` REST endpoint directly; this is a\n * plain typed-decision API, not chat/completion, so it does not go\n * through pi-ai's provider machinery.\n */\nimport { readEnv } from \"../env-manifest.js\";\n\n/** The current public Jev model id on OpenRouter. */\nexport const JEV_MODEL_ID = \"~typesafe/jev-latest\";\n\nconst OPENROUTER_DECISIONS_URL = \"https://openrouter.ai/api/alpha/decisions\";\n\n/**\n * Any value Jev accepts as text-bearing structure: a string, a JSON object,\n * an array, or `null`. State, instructions, and criteria descriptions all\n * take this shape; Jev is trained to read the structure, so objects with\n * labelled keys are preferred over string templates.\n */\nexport type JevEntry = string | number | boolean | null | JevEntry[] | { [key: string]: JevEntry };\n\n/** A shared caller-facing question shape; translated to OpenRouter's wire format below. */\nexport type JevQuestion =\n | {\n type: \"boolean\";\n instructions: JevEntry;\n /** Optional descriptions of the yes / no outcomes. */\n criteria?: { true?: JevEntry; false?: JevEntry };\n }\n | { type: \"choice\"; instructions: JevEntry; criteria: Record<string, JevEntry> }\n | { type: \"score\"; instructions: JevEntry; criteria: readonly JevEntry[] };\n\nexport type JevQuestions = Record<string, JevQuestion>;\n\nexport type JevAnswer<QUESTION extends JevQuestion> = QUESTION extends { type: \"choice\" }\n ? {\n type: \"choice\";\n choice: string;\n probabilities?: Record<string, number>;\n /** 0-1 statistic over `probabilities`; low means no option clearly fits. */\n confidence?: number;\n }\n : QUESTION extends { type: \"score\" }\n ? {\n type: \"score\";\n /** Expected level index; fractional between levels. */\n score: number;\n probabilities?: Record<string, number>;\n /** Level index -> criterion text, as echoed by Jev. */\n legend?: Record<string, string>;\n confidence?: number;\n }\n : { type: \"boolean\"; probability: number };\n\nexport interface JevResult<QUESTIONS extends JevQuestions> {\n readonly answers: { [ID in keyof QUESTIONS]: JevAnswer<QUESTIONS[ID]> };\n readonly usage: {\n inputTokens: number | undefined;\n outputTokens: number | undefined;\n cost: number | undefined;\n };\n readonly model: string;\n}\n\nexport class JevNotConfiguredError extends Error {\n constructor() {\n super(\n \"Jev requires OPENROUTER_API_KEY (an OpenRouter API key). Set it in the environment before calling evaluateWithJev().\",\n );\n this.name = \"JevNotConfiguredError\";\n }\n}\n\nexport class JevRequestError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n ) {\n super(message);\n this.name = \"JevRequestError\";\n }\n}\n\nexport interface EvaluateWithJevOptions {\n /** Evaluation model id; defaults to the current public Jev model. */\n model?: string;\n abortSignal?: AbortSignal;\n headers?: Record<string, string>;\n}\n\n// ── wire format (OpenRouter decisions API) ──────────────────────────────────\n\ntype OpenRouterQuestion =\n | {\n type: \"noul\";\n instructions: JevEntry;\n criteria: { true: JevEntry; false: JevEntry };\n }\n | { type: \"choice\"; instructions: JevEntry; criteria: Record<string, JevEntry> }\n | { type: \"score\"; instructions: JevEntry; criteria: readonly JevEntry[] };\n\ninterface OpenRouterAnswer {\n type: \"noul\" | \"choice\" | \"score\";\n noul?: number;\n choice?: string;\n score?: number;\n probabilities?: Record<string, number>;\n confidence?: number;\n legend?: Record<string, string>;\n}\n\ninterface OpenRouterDecisionsResponse {\n model: string;\n answers: Record<string, OpenRouterAnswer>;\n usage?: { input_tokens?: number; output_tokens?: number; cost?: number };\n error?: { message: string; code?: number };\n}\n\nfunction toOpenRouterQuestion(question: JevQuestion): OpenRouterQuestion {\n if (question.type === \"boolean\") {\n return {\n type: \"noul\",\n instructions: question.instructions,\n criteria: {\n true: question.criteria?.true ?? \"Yes\",\n false: question.criteria?.false ?? \"No\",\n },\n };\n }\n return question;\n}\n\nfunction fromOpenRouterAnswer(answer: OpenRouterAnswer): JevAnswer<JevQuestion> {\n if (answer.type === \"noul\") {\n return { type: \"boolean\", probability: answer.noul ?? 0 };\n }\n if (answer.type === \"choice\") {\n return {\n type: \"choice\",\n choice: answer.choice ?? \"\",\n probabilities: answer.probabilities,\n confidence: answer.confidence,\n };\n }\n return {\n type: \"score\",\n score: answer.score ?? 0,\n probabilities: answer.probabilities,\n legend: answer.legend,\n confidence: answer.confidence,\n };\n}\n\n/**\n * Evaluate one or more typed questions against a shared `state` using Jev,\n * reached through OpenRouter's decisions API. Every question is scored\n * independently against the same state in a single request; batching\n * questions here is cheap (they share the input) and is preferred over\n * separate calls per question.\n */\nexport async function evaluateWithJev<const QUESTIONS extends JevQuestions>(\n state: JevEntry,\n questions: QUESTIONS,\n options: EvaluateWithJevOptions = {},\n): Promise<JevResult<QUESTIONS>> {\n const apiKey = readEnv(\"OPENROUTER_API_KEY\");\n if (!apiKey) throw new JevNotConfiguredError();\n\n const wireQuestions: Record<string, OpenRouterQuestion> = {};\n for (const [id, question] of Object.entries(questions)) {\n wireQuestions[id] = toOpenRouterQuestion(question);\n }\n\n const response = await fetch(OPENROUTER_DECISIONS_URL, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n body: JSON.stringify({\n model: options.model ?? JEV_MODEL_ID,\n state,\n questions: wireQuestions,\n }),\n signal: options.abortSignal,\n });\n\n const body = (await response.json()) as OpenRouterDecisionsResponse;\n if (!response.ok || body.error) {\n throw new JevRequestError(\n body.error?.message ?? `Jev request failed with status ${response.status}`,\n body.error?.code ?? response.status,\n );\n }\n\n const answers = {} as { [ID in keyof QUESTIONS]: JevAnswer<QUESTIONS[ID]> };\n for (const id of Object.keys(questions)) {\n const answer = body.answers[id];\n if (!answer) throw new JevRequestError(`Jev response missing answer for \"${id}\"`, 502);\n (answers as Record<string, JevAnswer<JevQuestion>>)[id] = fromOpenRouterAnswer(answer);\n }\n\n return {\n answers,\n usage: {\n inputTokens: body.usage?.input_tokens,\n outputTokens: body.usage?.output_tokens,\n cost: body.usage?.cost,\n },\n model: body.model,\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presenter.d.ts","sourceRoot":"","sources":["../../src/harness/presenter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,GAAG,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAEV,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAOtD,OAAO,KAAK,EAAE,qBAAqB,EAA4B,MAAM,aAAa,CAAC;AACnF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AA+DxE,wBAAgB,cAAc,IAAI,kBAAkB,CAkCnD;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE;IACP,SAAS,EAAE,qBAAqB,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC,GACA,eAAe,CAsEjB;AAOD,wBAAgB,yBAAyB,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEzF;
|
|
1
|
+
{"version":3,"file":"presenter.d.ts","sourceRoot":"","sources":["../../src/harness/presenter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,GAAG,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAEV,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAOtD,OAAO,KAAK,EAAE,qBAAqB,EAA4B,MAAM,aAAa,CAAC;AACnF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AA+DxE,wBAAgB,cAAc,IAAI,kBAAkB,CAkCnD;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE;IACP,SAAS,EAAE,qBAAqB,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC,GACA,eAAe,CAsEjB;AAOD,wBAAgB,yBAAyB,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEzF;AAqKD,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,qBAAqB,EAChC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE;IACR,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GACA,OAAO,CAAC,IAAI,CAAC,CAsBf;AAsFD,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiG/E;AAucD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IACjD,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,WAAW,EAAE,UAAU,CAAC,OAAO,2BAA2B,CAAC,CAAC;CAC7D,GAAG,IAAI,CAiBP"}
|
|
@@ -156,9 +156,10 @@ export function isEventTriggerAttribution(triggerAttribution) {
|
|
|
156
156
|
}
|
|
157
157
|
function extractToolLabel(toolName, args) {
|
|
158
158
|
const label = args?.label;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
const text = typeof label === "string" ? label.trim() || toolName : toolName;
|
|
160
|
+
// Jev judgments are calibrated probabilities, not the model's own guess;
|
|
161
|
+
// name the tool so the user can tell which steps came from it.
|
|
162
|
+
return toolName === "jev" ? `jev · ${text}` : text;
|
|
162
163
|
}
|
|
163
164
|
/** Non-subagent tool activity lines; subagent calls render as the dashboard. */
|
|
164
165
|
function formatToolProgress(runState) {
|