modelstat 0.0.46 → 0.0.48
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/cli.mjs +637 -55
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -78,7 +78,7 @@ var init_git = __esm({
|
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
// ../../packages/core/src/enums.ts
|
|
81
|
-
var TOOLS, PROVIDERS, IDENTITY_OWNER_SCOPES, INSTALL_METHODS, OS_FAMILIES, EVENT_KINDS, COMPANION_PHASES, CLASSIFICATION_CONFIDENCE;
|
|
81
|
+
var TOOLS, PROVIDERS, IDENTITY_OWNER_SCOPES, INSTALL_METHODS, OS_FAMILIES, EVENT_KINDS, TOOL_CALL_STATUSES, COMPANION_PHASES, CLASSIFICATION_CONFIDENCE;
|
|
82
82
|
var init_enums = __esm({
|
|
83
83
|
"../../packages/core/src/enums.ts"() {
|
|
84
84
|
"use strict";
|
|
@@ -162,6 +162,13 @@ var init_enums = __esm({
|
|
|
162
162
|
"tool_result",
|
|
163
163
|
"summary"
|
|
164
164
|
];
|
|
165
|
+
TOOL_CALL_STATUSES = [
|
|
166
|
+
"success",
|
|
167
|
+
"error",
|
|
168
|
+
"denied",
|
|
169
|
+
"timeout",
|
|
170
|
+
"unknown"
|
|
171
|
+
];
|
|
165
172
|
COMPANION_PHASES = [
|
|
166
173
|
"starting",
|
|
167
174
|
"discovering",
|
|
@@ -4304,7 +4311,7 @@ var init_zod = __esm({
|
|
|
4304
4311
|
});
|
|
4305
4312
|
|
|
4306
4313
|
// ../../packages/core/src/schemas.ts
|
|
4307
|
-
var TokenUsage, GitContext, RawEvent, RedactionReport, TaxonomyHintRooted, Segment, IngestBatch, HeartbeatPayload, DeviceEnrollment, DeviceSelfRegister, DeviceClaimRequest, ProcessingMetadata, RedactionPolicy, DetectedInstallation, DetectedIdentity, DiscoveryReport, ClassificationConfidenceEnum;
|
|
4314
|
+
var TokenUsage, GitContext, RawEvent, RedactionReport, TaxonomyHintRooted, Segment, ToolCallWire, IngestBatch, HeartbeatPayload, DeviceEnrollment, DeviceSelfRegister, DeviceClaimRequest, ProcessingMetadata, RedactionPolicy, DetectedInstallation, DetectedIdentity, DiscoveryReport, ClassificationConfidenceEnum;
|
|
4308
4315
|
var init_schemas = __esm({
|
|
4309
4316
|
"../../packages/core/src/schemas.ts"() {
|
|
4310
4317
|
"use strict";
|
|
@@ -4409,6 +4416,49 @@ var init_schemas = __esm({
|
|
|
4409
4416
|
* Reserved for server-side similarity / clustering. */
|
|
4410
4417
|
abstract_embedding: external_exports.array(external_exports.number()).length(384).optional()
|
|
4411
4418
|
});
|
|
4419
|
+
ToolCallWire = external_exports.object({
|
|
4420
|
+
/** tool_use block `id` / codex `call_id`; parsers fall back to a
|
|
4421
|
+
* deterministic `tc_<djb2-base36>` of `${source_event_id}|${call_index}`
|
|
4422
|
+
* when the source line carries no id. */
|
|
4423
|
+
external_call_id: external_exports.string().max(120),
|
|
4424
|
+
/** Tool-local session id — same id space as RawEvent.session_id. */
|
|
4425
|
+
session_id: external_exports.string().max(120),
|
|
4426
|
+
/** The RawEvent that contained the tool_use (dedupe/replay anchor). */
|
|
4427
|
+
source_event_id: external_exports.string(),
|
|
4428
|
+
/** Segment containing source_event_id — filled by the companion at
|
|
4429
|
+
* batch-build time when known, else null. */
|
|
4430
|
+
segment_id: external_exports.string().max(64).nullable().default(null),
|
|
4431
|
+
/** The agent that made the call (TOOLS enum — "tool" in legacy naming). */
|
|
4432
|
+
agent: external_exports.enum(TOOLS),
|
|
4433
|
+
/** `builtin` or `mcp:<server>`. */
|
|
4434
|
+
server: external_exports.string().max(120),
|
|
4435
|
+
/** Bare tool name (`Bash`, `create_pr`) — normalised vendor identifier. */
|
|
4436
|
+
name: external_exports.string().max(120),
|
|
4437
|
+
turn_index: external_exports.number().int().nonnegative().nullable(),
|
|
4438
|
+
/** Ordinal of the call within its source event (0-based). */
|
|
4439
|
+
call_index: external_exports.number().int().nonnegative(),
|
|
4440
|
+
/** ts of the line carrying the tool_use. */
|
|
4441
|
+
started_at: external_exports.string().datetime({ offset: true }),
|
|
4442
|
+
/** ts of the line carrying the matching tool_result; null if unmatched. */
|
|
4443
|
+
ended_at: external_exports.string().datetime({ offset: true }).nullable(),
|
|
4444
|
+
status: external_exports.enum(TOOL_CALL_STATUSES),
|
|
4445
|
+
/** Hex sha256 of JSON.stringify(input); `""` when the call had no input. */
|
|
4446
|
+
args_hash: external_exports.string().max(64),
|
|
4447
|
+
/** Sha256 of the sorted top-level arg key names joined by `,`; the
|
|
4448
|
+
* literal `none` when input is not a non-empty object. */
|
|
4449
|
+
signature_hash: external_exports.string().max(64),
|
|
4450
|
+
/** UTF-8 byte length of JSON.stringify(input); 0 if none. */
|
|
4451
|
+
args_bytes: external_exports.number().int().nonnegative(),
|
|
4452
|
+
/** UTF-8 byte length of JSON.stringify(tool_result content); 0 if
|
|
4453
|
+
* unmatched/empty. */
|
|
4454
|
+
result_bytes: external_exports.number().int().nonnegative(),
|
|
4455
|
+
/** Model of the assistant message that issued the call. `<synthetic>`
|
|
4456
|
+
* kept verbatim per the PR #12 attribution rules. */
|
|
4457
|
+
model: external_exports.string().max(120).nullable(),
|
|
4458
|
+
/** ONLY for shell-ish tools: command verbs from the fixed allowlist
|
|
4459
|
+
* (@modelstat/parsers/shell-families). Never raw command text. */
|
|
4460
|
+
command_families: external_exports.array(external_exports.string().max(40)).max(3).default([])
|
|
4461
|
+
});
|
|
4412
4462
|
IngestBatch = external_exports.object({
|
|
4413
4463
|
batch_id: external_exports.string(),
|
|
4414
4464
|
// ULID
|
|
@@ -4416,6 +4466,10 @@ var init_schemas = __esm({
|
|
|
4416
4466
|
agent_version: external_exports.string().max(40),
|
|
4417
4467
|
events: external_exports.array(RawEvent).max(1e4),
|
|
4418
4468
|
segments: external_exports.array(Segment).max(2e3).default([]),
|
|
4469
|
+
/** Per-call tool invocations (additive — old agents omit it, old
|
|
4470
|
+
* servers ignore it). See ToolCallWire for the privacy contract:
|
|
4471
|
+
* hashes / byte sizes / allowlisted verbs only, never payloads. */
|
|
4472
|
+
tool_calls: external_exports.array(ToolCallWire).max(2e4).default([]),
|
|
4419
4473
|
/** Optional per-session metadata hint: which installation produced them, etc. */
|
|
4420
4474
|
session_installs: external_exports.record(
|
|
4421
4475
|
external_exports.string(),
|
|
@@ -4684,22 +4738,222 @@ var init_src = __esm({
|
|
|
4684
4738
|
}
|
|
4685
4739
|
});
|
|
4686
4740
|
|
|
4687
|
-
// ../../packages/parsers/src/
|
|
4741
|
+
// ../../packages/parsers/src/shell-families/index.ts
|
|
4742
|
+
function extractCommandFamilies(command) {
|
|
4743
|
+
const families = [];
|
|
4744
|
+
for (const part of splitCommandParts(command)) {
|
|
4745
|
+
const verb = leadingVerb(part);
|
|
4746
|
+
if (!verb || !ALLOWLIST.has(verb)) continue;
|
|
4747
|
+
if (!families.includes(verb)) families.push(verb);
|
|
4748
|
+
if (families.length >= MAX_COMMAND_FAMILIES) break;
|
|
4749
|
+
}
|
|
4750
|
+
return families;
|
|
4751
|
+
}
|
|
4752
|
+
function splitCommandParts(command) {
|
|
4753
|
+
const parts = [];
|
|
4754
|
+
let current = "";
|
|
4755
|
+
let inSingle = false;
|
|
4756
|
+
let inDouble = false;
|
|
4757
|
+
for (let i = 0; i < command.length; i++) {
|
|
4758
|
+
const ch = command[i];
|
|
4759
|
+
if (!inSingle && ch === "\\") {
|
|
4760
|
+
current += ch + (command[i + 1] ?? "");
|
|
4761
|
+
i++;
|
|
4762
|
+
continue;
|
|
4763
|
+
}
|
|
4764
|
+
if (ch === "'" && !inDouble) {
|
|
4765
|
+
inSingle = !inSingle;
|
|
4766
|
+
current += ch;
|
|
4767
|
+
continue;
|
|
4768
|
+
}
|
|
4769
|
+
if (ch === '"' && !inSingle) {
|
|
4770
|
+
inDouble = !inDouble;
|
|
4771
|
+
current += ch;
|
|
4772
|
+
continue;
|
|
4773
|
+
}
|
|
4774
|
+
if (!inSingle && !inDouble) {
|
|
4775
|
+
if (ch === ";" || ch === "|" || ch === "\n") {
|
|
4776
|
+
parts.push(current);
|
|
4777
|
+
current = "";
|
|
4778
|
+
continue;
|
|
4779
|
+
}
|
|
4780
|
+
if (ch === "&" && command[i + 1] === "&") {
|
|
4781
|
+
parts.push(current);
|
|
4782
|
+
current = "";
|
|
4783
|
+
i++;
|
|
4784
|
+
continue;
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
current += ch;
|
|
4788
|
+
}
|
|
4789
|
+
parts.push(current);
|
|
4790
|
+
return parts;
|
|
4791
|
+
}
|
|
4792
|
+
function leadingVerb(part) {
|
|
4793
|
+
const tokens = part.trim().split(/\s+/);
|
|
4794
|
+
let i = 0;
|
|
4795
|
+
while (i < tokens.length) {
|
|
4796
|
+
const tok = stripQuotes(tokens[i] ?? "");
|
|
4797
|
+
if (tok === "") {
|
|
4798
|
+
i++;
|
|
4799
|
+
continue;
|
|
4800
|
+
}
|
|
4801
|
+
if (VAR_ASSIGNMENT.test(tok)) {
|
|
4802
|
+
i++;
|
|
4803
|
+
continue;
|
|
4804
|
+
}
|
|
4805
|
+
if (WRAPPERS.has(tok)) {
|
|
4806
|
+
i++;
|
|
4807
|
+
while (i < tokens.length && (tokens[i] ?? "").startsWith("-")) i++;
|
|
4808
|
+
continue;
|
|
4809
|
+
}
|
|
4810
|
+
const base = tok.split("/").pop() ?? tok;
|
|
4811
|
+
return base === "" ? null : base;
|
|
4812
|
+
}
|
|
4813
|
+
return null;
|
|
4814
|
+
}
|
|
4815
|
+
function stripQuotes(token) {
|
|
4816
|
+
if (token.length >= 2) {
|
|
4817
|
+
const first = token[0];
|
|
4818
|
+
const last = token[token.length - 1];
|
|
4819
|
+
if (first === "'" && last === "'" || first === '"' && last === '"') {
|
|
4820
|
+
return token.slice(1, -1);
|
|
4821
|
+
}
|
|
4822
|
+
}
|
|
4823
|
+
return token;
|
|
4824
|
+
}
|
|
4825
|
+
var SHELL_FAMILY_ALLOWLIST, MAX_COMMAND_FAMILIES, ALLOWLIST, WRAPPERS, VAR_ASSIGNMENT;
|
|
4826
|
+
var init_shell_families = __esm({
|
|
4827
|
+
"../../packages/parsers/src/shell-families/index.ts"() {
|
|
4828
|
+
"use strict";
|
|
4829
|
+
SHELL_FAMILY_ALLOWLIST = [
|
|
4830
|
+
"git",
|
|
4831
|
+
"npm",
|
|
4832
|
+
"pnpm",
|
|
4833
|
+
"npx",
|
|
4834
|
+
"yarn",
|
|
4835
|
+
"node",
|
|
4836
|
+
"python",
|
|
4837
|
+
"python3",
|
|
4838
|
+
"pytest",
|
|
4839
|
+
"pip",
|
|
4840
|
+
"pip3",
|
|
4841
|
+
"cargo",
|
|
4842
|
+
"rustc",
|
|
4843
|
+
"go",
|
|
4844
|
+
"make",
|
|
4845
|
+
"cmake",
|
|
4846
|
+
"docker",
|
|
4847
|
+
"docker-compose",
|
|
4848
|
+
"kubectl",
|
|
4849
|
+
"helm",
|
|
4850
|
+
"terraform",
|
|
4851
|
+
"gh",
|
|
4852
|
+
"aws",
|
|
4853
|
+
"gcloud",
|
|
4854
|
+
"az",
|
|
4855
|
+
"curl",
|
|
4856
|
+
"wget",
|
|
4857
|
+
"rg",
|
|
4858
|
+
"grep",
|
|
4859
|
+
"find",
|
|
4860
|
+
"sed",
|
|
4861
|
+
"awk",
|
|
4862
|
+
"jq",
|
|
4863
|
+
"psql",
|
|
4864
|
+
"mysql",
|
|
4865
|
+
"redis-cli",
|
|
4866
|
+
"brew",
|
|
4867
|
+
"apt",
|
|
4868
|
+
"tsx",
|
|
4869
|
+
"vitest",
|
|
4870
|
+
"jest",
|
|
4871
|
+
"playwright",
|
|
4872
|
+
"ruby",
|
|
4873
|
+
"bundle",
|
|
4874
|
+
"mvn",
|
|
4875
|
+
"gradle",
|
|
4876
|
+
"ls",
|
|
4877
|
+
"cat"
|
|
4878
|
+
];
|
|
4879
|
+
MAX_COMMAND_FAMILIES = 3;
|
|
4880
|
+
ALLOWLIST = new Set(SHELL_FAMILY_ALLOWLIST);
|
|
4881
|
+
WRAPPERS = /* @__PURE__ */ new Set(["sudo", "env", "time", "nice"]);
|
|
4882
|
+
VAR_ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
4883
|
+
}
|
|
4884
|
+
});
|
|
4885
|
+
|
|
4886
|
+
// ../../packages/parsers/src/tool-hash/index.ts
|
|
4688
4887
|
import { createHash } from "crypto";
|
|
4888
|
+
function hashArgs(input) {
|
|
4889
|
+
if (input === void 0 || input === null) {
|
|
4890
|
+
return { args_hash: "", signature_hash: SIGNATURE_NONE, args_bytes: 0 };
|
|
4891
|
+
}
|
|
4892
|
+
const json = JSON.stringify(input);
|
|
4893
|
+
if (json === void 0) {
|
|
4894
|
+
return { args_hash: "", signature_hash: SIGNATURE_NONE, args_bytes: 0 };
|
|
4895
|
+
}
|
|
4896
|
+
const argsHash = createHash("sha256").update(json).digest("hex");
|
|
4897
|
+
let signatureHash = SIGNATURE_NONE;
|
|
4898
|
+
if (typeof input === "object" && !Array.isArray(input)) {
|
|
4899
|
+
const keys = Object.keys(input).sort();
|
|
4900
|
+
if (keys.length > 0) {
|
|
4901
|
+
signatureHash = createHash("sha256").update(keys.join(",")).digest("hex");
|
|
4902
|
+
}
|
|
4903
|
+
}
|
|
4904
|
+
return {
|
|
4905
|
+
args_hash: argsHash,
|
|
4906
|
+
signature_hash: signatureHash,
|
|
4907
|
+
args_bytes: Buffer.byteLength(json, "utf8")
|
|
4908
|
+
};
|
|
4909
|
+
}
|
|
4910
|
+
function jsonBytes(value) {
|
|
4911
|
+
if (value === void 0 || value === null || value === "") return 0;
|
|
4912
|
+
const json = JSON.stringify(value);
|
|
4913
|
+
return json === void 0 ? 0 : Buffer.byteLength(json, "utf8");
|
|
4914
|
+
}
|
|
4915
|
+
function normalizeToolName(raw) {
|
|
4916
|
+
const cleaned = raw.normalize("NFC").trim().replace(UUID_RE, "<dyn>").replace(HEX_TAIL_RE, "<dyn>");
|
|
4917
|
+
return cleaned.slice(0, 120);
|
|
4918
|
+
}
|
|
4919
|
+
function splitObservedToolName(observed) {
|
|
4920
|
+
const m = /^mcp__([^_].*?)__(.+)$/.exec(observed.trim());
|
|
4921
|
+
if (m?.[1] && m[2]) {
|
|
4922
|
+
return {
|
|
4923
|
+
server: `mcp:${normalizeToolName(m[1]).slice(0, 116)}`,
|
|
4924
|
+
name: normalizeToolName(m[2])
|
|
4925
|
+
};
|
|
4926
|
+
}
|
|
4927
|
+
return { server: "builtin", name: normalizeToolName(observed) };
|
|
4928
|
+
}
|
|
4929
|
+
function toolIdentity(server, name) {
|
|
4930
|
+
return server === "builtin" ? name : `${server}/${name}`;
|
|
4931
|
+
}
|
|
4932
|
+
function fallbackCallId(sourceEventId2, callIndex) {
|
|
4933
|
+
const s = `${sourceEventId2}|${callIndex}`;
|
|
4934
|
+
let h = 5381n;
|
|
4935
|
+
for (let i = 0; i < s.length; i++) {
|
|
4936
|
+
h = h * 33n ^ BigInt(s.charCodeAt(i));
|
|
4937
|
+
h &= 0xffffffffffffffffn;
|
|
4938
|
+
}
|
|
4939
|
+
return `tc_${h.toString(36)}`;
|
|
4940
|
+
}
|
|
4941
|
+
var SIGNATURE_NONE, UUID_RE, HEX_TAIL_RE;
|
|
4942
|
+
var init_tool_hash = __esm({
|
|
4943
|
+
"../../packages/parsers/src/tool-hash/index.ts"() {
|
|
4944
|
+
"use strict";
|
|
4945
|
+
SIGNATURE_NONE = "none";
|
|
4946
|
+
UUID_RE = /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g;
|
|
4947
|
+
HEX_TAIL_RE = /[0-9a-fA-F]{8,}(?=$|[^0-9a-zA-Z])/g;
|
|
4948
|
+
}
|
|
4949
|
+
});
|
|
4950
|
+
|
|
4951
|
+
// ../../packages/parsers/src/claude-code/index.ts
|
|
4952
|
+
import { createHash as createHash2 } from "crypto";
|
|
4689
4953
|
import { createReadStream, existsSync as existsSync2, readdirSync } from "fs";
|
|
4690
4954
|
import { stat } from "fs/promises";
|
|
4691
4955
|
import { dirname as dirname2, join } from "path";
|
|
4692
4956
|
import { createInterface } from "readline";
|
|
4693
|
-
function countToolCalls(content) {
|
|
4694
|
-
const counts = {};
|
|
4695
|
-
if (!Array.isArray(content)) return counts;
|
|
4696
|
-
for (const block of content) {
|
|
4697
|
-
if (block && block.type === "tool_use" && typeof block.name === "string" && block.name) {
|
|
4698
|
-
counts[block.name] = (counts[block.name] ?? 0) + 1;
|
|
4699
|
-
}
|
|
4700
|
-
}
|
|
4701
|
-
return counts;
|
|
4702
|
-
}
|
|
4703
4957
|
function extractExcerpt(content) {
|
|
4704
4958
|
if (!content) return void 0;
|
|
4705
4959
|
let text = "";
|
|
@@ -4722,8 +4976,41 @@ function extractExcerpt(content) {
|
|
|
4722
4976
|
const truncated = cleaned.slice(0, 320);
|
|
4723
4977
|
return truncated.length > 0 ? truncated : void 0;
|
|
4724
4978
|
}
|
|
4979
|
+
function commandFamiliesFor(server, name, input) {
|
|
4980
|
+
if (server !== "builtin" || !SHELL_TOOL_NAMES.has(name)) return [];
|
|
4981
|
+
if (typeof input !== "object" || input === null) return [];
|
|
4982
|
+
const command = input.command;
|
|
4983
|
+
return typeof command === "string" ? extractCommandFamilies(command) : [];
|
|
4984
|
+
}
|
|
4985
|
+
function buildToolCallDraft(opts) {
|
|
4986
|
+
const { server, name } = splitObservedToolName(opts.observedName);
|
|
4987
|
+
const hashes = hashArgs(opts.input);
|
|
4988
|
+
return {
|
|
4989
|
+
external_call_id: typeof opts.rawCallId === "string" && opts.rawCallId.trim() !== "" ? opts.rawCallId.trim().slice(0, 120) : fallbackCallId(opts.sourceEventId, opts.callIndex),
|
|
4990
|
+
session_id: opts.sessionId,
|
|
4991
|
+
source_event_id: opts.sourceEventId,
|
|
4992
|
+
agent: "claude_code",
|
|
4993
|
+
server,
|
|
4994
|
+
name,
|
|
4995
|
+
// This parser never derives a turn index (events above carry
|
|
4996
|
+
// turn_index: null too), so per-call records can't either.
|
|
4997
|
+
turn_index: null,
|
|
4998
|
+
call_index: opts.callIndex,
|
|
4999
|
+
started_at: opts.startedAt,
|
|
5000
|
+
ended_at: null,
|
|
5001
|
+
status: "unknown",
|
|
5002
|
+
args_hash: hashes.args_hash,
|
|
5003
|
+
signature_hash: hashes.signature_hash,
|
|
5004
|
+
args_bytes: hashes.args_bytes,
|
|
5005
|
+
result_bytes: 0,
|
|
5006
|
+
model: opts.model,
|
|
5007
|
+
command_families: commandFamiliesFor(server, name, opts.input)
|
|
5008
|
+
};
|
|
5009
|
+
}
|
|
4725
5010
|
async function parseClaudeCodeJsonl(ctx) {
|
|
4726
5011
|
const events = [];
|
|
5012
|
+
const toolCalls = [];
|
|
5013
|
+
const pendingByCallId = /* @__PURE__ */ new Map();
|
|
4727
5014
|
let chunk = [];
|
|
4728
5015
|
let emitted = 0;
|
|
4729
5016
|
const emit = async (e) => {
|
|
@@ -4826,6 +5113,32 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4826
5113
|
}
|
|
4827
5114
|
const slug = guessRepoSlugFromPath(cwd);
|
|
4828
5115
|
const excerpt = extractExcerpt(a.message?.content);
|
|
5116
|
+
const aggregate = {};
|
|
5117
|
+
const blocks = Array.isArray(a.message?.content) ? a.message.content : [];
|
|
5118
|
+
let callIndex = 0;
|
|
5119
|
+
for (const block of blocks) {
|
|
5120
|
+
if (!block || block.type !== "tool_use") continue;
|
|
5121
|
+
const index = callIndex;
|
|
5122
|
+
callIndex += 1;
|
|
5123
|
+
const observed = typeof block.name === "string" ? block.name.trim() : "";
|
|
5124
|
+
if (!observed) continue;
|
|
5125
|
+
const draft = buildToolCallDraft({
|
|
5126
|
+
observedName: observed,
|
|
5127
|
+
rawCallId: block.id,
|
|
5128
|
+
input: block.input,
|
|
5129
|
+
sessionId,
|
|
5130
|
+
sourceEventId: eventId,
|
|
5131
|
+
callIndex: index,
|
|
5132
|
+
startedAt: a.timestamp,
|
|
5133
|
+
// Model verbatim from the issuing assistant message —
|
|
5134
|
+
// including "<synthetic>" (same rule as the event below).
|
|
5135
|
+
model: a.message?.model ?? null
|
|
5136
|
+
});
|
|
5137
|
+
const identity = toolIdentity(draft.server, draft.name);
|
|
5138
|
+
aggregate[identity] = (aggregate[identity] ?? 0) + 1;
|
|
5139
|
+
toolCalls.push(draft);
|
|
5140
|
+
if (typeof block.id === "string" && block.id) pendingByCallId.set(block.id, draft);
|
|
5141
|
+
}
|
|
4829
5142
|
await emit({
|
|
4830
5143
|
source_event_id: eventId,
|
|
4831
5144
|
ts: a.timestamp,
|
|
@@ -4852,7 +5165,7 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4852
5165
|
reasoning: 0
|
|
4853
5166
|
},
|
|
4854
5167
|
duration_ms: null,
|
|
4855
|
-
tool_calls:
|
|
5168
|
+
tool_calls: aggregate,
|
|
4856
5169
|
files_touched: [],
|
|
4857
5170
|
...excerpt ? { content_excerpt: excerpt } : {},
|
|
4858
5171
|
source_file: ctx.sourceFile,
|
|
@@ -4865,6 +5178,20 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4865
5178
|
});
|
|
4866
5179
|
} else if (obj.type === "user") {
|
|
4867
5180
|
const u = obj;
|
|
5181
|
+
const uContent = u.message?.content;
|
|
5182
|
+
if (Array.isArray(uContent)) {
|
|
5183
|
+
for (const block of uContent) {
|
|
5184
|
+
if (!block || block.type !== "tool_result") continue;
|
|
5185
|
+
const ref = block.tool_use_id;
|
|
5186
|
+
if (typeof ref !== "string") continue;
|
|
5187
|
+
const draft = pendingByCallId.get(ref);
|
|
5188
|
+
if (!draft) continue;
|
|
5189
|
+
pendingByCallId.delete(ref);
|
|
5190
|
+
draft.ended_at = u.timestamp;
|
|
5191
|
+
draft.status = block.is_error === true ? "error" : "success";
|
|
5192
|
+
draft.result_bytes = jsonBytes(block.content);
|
|
5193
|
+
}
|
|
5194
|
+
}
|
|
4868
5195
|
if (!u.uuid || !sessionId) {
|
|
4869
5196
|
skipped += 1;
|
|
4870
5197
|
continue;
|
|
@@ -4896,6 +5223,30 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4896
5223
|
source_byte_offset: offsetAtLineStart,
|
|
4897
5224
|
billing: "subscription"
|
|
4898
5225
|
});
|
|
5226
|
+
} else if (obj.type === "tool_use") {
|
|
5227
|
+
const t = obj;
|
|
5228
|
+
const observed = typeof t.name === "string" ? t.name.trim() : "";
|
|
5229
|
+
const ts = typeof t.timestamp === "string" ? t.timestamp : null;
|
|
5230
|
+
const sid = (typeof t.sessionId === "string" ? t.sessionId : null) ?? sessionId;
|
|
5231
|
+
if (!observed || !ts || !sid) {
|
|
5232
|
+
skipped += 1;
|
|
5233
|
+
continue;
|
|
5234
|
+
}
|
|
5235
|
+
const draft = buildToolCallDraft({
|
|
5236
|
+
observedName: observed,
|
|
5237
|
+
rawCallId: t.id,
|
|
5238
|
+
input: t.input,
|
|
5239
|
+
sessionId: sid,
|
|
5240
|
+
sourceEventId: sourceEventId(ctx.deviceId, ctx.sourceFile, offsetAtLineStart),
|
|
5241
|
+
callIndex: 0,
|
|
5242
|
+
startedAt: ts,
|
|
5243
|
+
// No issuing assistant message on this line — attribute to the
|
|
5244
|
+
// session's last real model, same as user_message attribution
|
|
5245
|
+
// (lastModel never holds "<synthetic>", per the rule above).
|
|
5246
|
+
model: lastModel
|
|
5247
|
+
});
|
|
5248
|
+
toolCalls.push(draft);
|
|
5249
|
+
if (typeof t.id === "string" && t.id) pendingByCallId.set(t.id, draft);
|
|
4899
5250
|
} else {
|
|
4900
5251
|
skipped += 1;
|
|
4901
5252
|
}
|
|
@@ -4903,6 +5254,7 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4903
5254
|
if (ctx.onEvents && chunk.length > 0) await ctx.onEvents(chunk);
|
|
4904
5255
|
return {
|
|
4905
5256
|
events,
|
|
5257
|
+
toolCalls,
|
|
4906
5258
|
stats: { rawLines, emittedEvents: emitted, skipped },
|
|
4907
5259
|
sourceFile: ctx.sourceFile
|
|
4908
5260
|
};
|
|
@@ -4917,16 +5269,26 @@ async function quickChecksum(path5) {
|
|
|
4917
5269
|
start: Math.max(0, st.size - 4096),
|
|
4918
5270
|
encoding: "utf8"
|
|
4919
5271
|
});
|
|
4920
|
-
const h =
|
|
5272
|
+
const h = createHash2("sha1");
|
|
4921
5273
|
for await (const chunk of stream) h.update(chunk);
|
|
4922
5274
|
return { size: st.size, mtime: st.mtimeMs, tailHash: h.digest("hex").slice(0, 16) };
|
|
4923
5275
|
}
|
|
5276
|
+
var SHELL_TOOL_NAMES;
|
|
4924
5277
|
var init_claude_code = __esm({
|
|
4925
5278
|
"../../packages/parsers/src/claude-code/index.ts"() {
|
|
4926
5279
|
"use strict";
|
|
4927
5280
|
init_src();
|
|
4928
|
-
init_types();
|
|
4929
5281
|
init_git();
|
|
5282
|
+
init_shell_families();
|
|
5283
|
+
init_tool_hash();
|
|
5284
|
+
init_types();
|
|
5285
|
+
SHELL_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
5286
|
+
"Bash",
|
|
5287
|
+
"shell",
|
|
5288
|
+
"local_shell_call",
|
|
5289
|
+
"exec_command",
|
|
5290
|
+
"run_terminal_cmd"
|
|
5291
|
+
]);
|
|
4930
5292
|
}
|
|
4931
5293
|
});
|
|
4932
5294
|
|
|
@@ -4939,8 +5301,90 @@ function deriveSessionIdFromRolloutPath(path5) {
|
|
|
4939
5301
|
);
|
|
4940
5302
|
return m ? m[1] ?? null : null;
|
|
4941
5303
|
}
|
|
5304
|
+
function commandFieldToString(cmd) {
|
|
5305
|
+
if (typeof cmd === "string") return cmd || null;
|
|
5306
|
+
if (Array.isArray(cmd)) {
|
|
5307
|
+
const parts = cmd.filter((p) => typeof p === "string");
|
|
5308
|
+
if (parts.length === 0) return null;
|
|
5309
|
+
const head = (parts[0] ?? "").split("/").pop() ?? "";
|
|
5310
|
+
const flag = parts[1] ?? "";
|
|
5311
|
+
if (parts.length >= 3 && SHELL_WRAPPER_BINARIES.has(head) && /^-[a-z]*c[a-z]*$/i.test(flag)) {
|
|
5312
|
+
return parts.slice(2).join("\n");
|
|
5313
|
+
}
|
|
5314
|
+
return parts.join(" ");
|
|
5315
|
+
}
|
|
5316
|
+
return null;
|
|
5317
|
+
}
|
|
5318
|
+
function firstString(...values) {
|
|
5319
|
+
for (const v of values) {
|
|
5320
|
+
if (typeof v === "string" && v) return v;
|
|
5321
|
+
}
|
|
5322
|
+
return null;
|
|
5323
|
+
}
|
|
5324
|
+
function extractToolCallPayload(pt, p) {
|
|
5325
|
+
const callId = firstString(p.call_id, p.id);
|
|
5326
|
+
const failed = p.status === "failed";
|
|
5327
|
+
if (pt === "local_shell_call") {
|
|
5328
|
+
const action = p.action && typeof p.action === "object" ? p.action : null;
|
|
5329
|
+
const command = commandFieldToString(action?.command);
|
|
5330
|
+
return {
|
|
5331
|
+
callId,
|
|
5332
|
+
server: "builtin",
|
|
5333
|
+
name: "shell",
|
|
5334
|
+
input: action,
|
|
5335
|
+
commandFamilies: command ? extractCommandFamilies(command) : [],
|
|
5336
|
+
failed
|
|
5337
|
+
};
|
|
5338
|
+
}
|
|
5339
|
+
const observed = firstString(p.name, p.tool);
|
|
5340
|
+
if (!observed) return null;
|
|
5341
|
+
let input = pt === "custom_tool_call" ? p.input : p.arguments ?? p.input;
|
|
5342
|
+
if (typeof input === "string" && !input.trim()) input = void 0;
|
|
5343
|
+
if (pt !== "custom_tool_call" && typeof input === "string") {
|
|
5344
|
+
try {
|
|
5345
|
+
input = JSON.parse(input);
|
|
5346
|
+
} catch {
|
|
5347
|
+
}
|
|
5348
|
+
}
|
|
5349
|
+
if (SHELL_TOOL_NAMES2.has(observed)) {
|
|
5350
|
+
const rec = input && typeof input === "object" && !Array.isArray(input) ? input : null;
|
|
5351
|
+
const command = commandFieldToString(
|
|
5352
|
+
rec?.command ?? rec?.cmd ?? (typeof input === "string" ? input : null)
|
|
5353
|
+
);
|
|
5354
|
+
return {
|
|
5355
|
+
callId,
|
|
5356
|
+
server: "builtin",
|
|
5357
|
+
name: "shell",
|
|
5358
|
+
input,
|
|
5359
|
+
commandFamilies: command ? extractCommandFamilies(command) : [],
|
|
5360
|
+
failed
|
|
5361
|
+
};
|
|
5362
|
+
}
|
|
5363
|
+
if (pt === "mcp_tool_call" && typeof p.server === "string" && p.server) {
|
|
5364
|
+
return {
|
|
5365
|
+
callId,
|
|
5366
|
+
// Mirror splitObservedToolName's cap: 116 + the `mcp:` prefix ≤ 120.
|
|
5367
|
+
server: `mcp:${normalizeToolName(p.server).slice(0, 116)}`,
|
|
5368
|
+
name: normalizeToolName(observed),
|
|
5369
|
+
input,
|
|
5370
|
+
commandFamilies: [],
|
|
5371
|
+
failed
|
|
5372
|
+
};
|
|
5373
|
+
}
|
|
5374
|
+
const { server, name } = splitObservedToolName(observed);
|
|
5375
|
+
return { callId, server, name, input, commandFamilies: [], failed };
|
|
5376
|
+
}
|
|
5377
|
+
function outputIndicatesError(p) {
|
|
5378
|
+
const out = p.output ?? p.result;
|
|
5379
|
+
if (out && typeof out === "object" && !Array.isArray(out)) {
|
|
5380
|
+
const o = out;
|
|
5381
|
+
if (o.success === false || o.is_error === true) return true;
|
|
5382
|
+
}
|
|
5383
|
+
return false;
|
|
5384
|
+
}
|
|
4942
5385
|
async function parseCodexRollout(ctx) {
|
|
4943
5386
|
const events = [];
|
|
5387
|
+
const toolCalls = [];
|
|
4944
5388
|
let chunk = [];
|
|
4945
5389
|
let emitted = 0;
|
|
4946
5390
|
const emit = async (e) => {
|
|
@@ -4969,6 +5413,9 @@ async function parseCodexRollout(ctx) {
|
|
|
4969
5413
|
let cwd = null;
|
|
4970
5414
|
let model = null;
|
|
4971
5415
|
let turnIndex = 0;
|
|
5416
|
+
let lastTs = null;
|
|
5417
|
+
const openCalls = /* @__PURE__ */ new Map();
|
|
5418
|
+
let pendingToolAggregate = {};
|
|
4972
5419
|
for await (const line of rl) {
|
|
4973
5420
|
const byteLen = Buffer.byteLength(line, "utf8") + 1;
|
|
4974
5421
|
const offsetAtLineStart = startOffset + bytePos;
|
|
@@ -4985,22 +5432,91 @@ async function parseCodexRollout(ctx) {
|
|
|
4985
5432
|
skipped += 1;
|
|
4986
5433
|
continue;
|
|
4987
5434
|
}
|
|
5435
|
+
const lineTs = obj.timestamp;
|
|
5436
|
+
if (typeof lineTs === "string" && lineTs) lastTs = lineTs;
|
|
4988
5437
|
if (obj.type === "session_meta") {
|
|
4989
5438
|
const m = obj;
|
|
4990
|
-
|
|
5439
|
+
const id = m.id ?? m.payload?.id ?? null;
|
|
5440
|
+
if (id && id !== sessionId) {
|
|
5441
|
+
sessionId = id;
|
|
5442
|
+
pendingToolAggregate = {};
|
|
5443
|
+
openCalls.clear();
|
|
5444
|
+
}
|
|
4991
5445
|
continue;
|
|
4992
5446
|
}
|
|
4993
5447
|
if (obj.type === "turn_context") {
|
|
4994
5448
|
const t = obj;
|
|
4995
|
-
cwd = t.cwd ?? cwd;
|
|
4996
|
-
model = t.model ?? model;
|
|
5449
|
+
cwd = t.cwd ?? t.payload?.cwd ?? cwd;
|
|
5450
|
+
model = t.model ?? t.payload?.model ?? model;
|
|
5451
|
+
continue;
|
|
5452
|
+
}
|
|
5453
|
+
if (obj.type === "response_item") {
|
|
5454
|
+
const r = obj;
|
|
5455
|
+
const payload = r.payload;
|
|
5456
|
+
const pt = payload && typeof payload.type === "string" ? payload.type : null;
|
|
5457
|
+
if (pt && TOOL_CALL_PAYLOAD_TYPES.has(pt) && sessionId) {
|
|
5458
|
+
const extracted = extractToolCallPayload(pt, payload);
|
|
5459
|
+
if (!extracted) {
|
|
5460
|
+
skipped += 1;
|
|
5461
|
+
continue;
|
|
5462
|
+
}
|
|
5463
|
+
const ts = r.timestamp ?? lastTs;
|
|
5464
|
+
if (!ts) {
|
|
5465
|
+
skipped += 1;
|
|
5466
|
+
continue;
|
|
5467
|
+
}
|
|
5468
|
+
const srcId = sourceEventId(ctx.deviceId, ctx.sourceFile, offsetAtLineStart);
|
|
5469
|
+
const { args_hash, signature_hash, args_bytes } = hashArgs(extracted.input);
|
|
5470
|
+
const draft = {
|
|
5471
|
+
external_call_id: (extracted.callId ?? fallbackCallId(srcId, 0)).slice(0, 120),
|
|
5472
|
+
session_id: sessionId,
|
|
5473
|
+
source_event_id: srcId,
|
|
5474
|
+
agent: "codex_cli",
|
|
5475
|
+
server: extracted.server,
|
|
5476
|
+
name: extracted.name,
|
|
5477
|
+
turn_index: turnIndex,
|
|
5478
|
+
// Each response_item line carries exactly one call.
|
|
5479
|
+
call_index: 0,
|
|
5480
|
+
started_at: ts,
|
|
5481
|
+
ended_at: null,
|
|
5482
|
+
status: extracted.failed ? "error" : "unknown",
|
|
5483
|
+
args_hash,
|
|
5484
|
+
signature_hash,
|
|
5485
|
+
args_bytes,
|
|
5486
|
+
result_bytes: 0,
|
|
5487
|
+
model,
|
|
5488
|
+
command_families: extracted.commandFamilies
|
|
5489
|
+
};
|
|
5490
|
+
toolCalls.push(draft);
|
|
5491
|
+
if (extracted.callId) openCalls.set(extracted.callId, draft);
|
|
5492
|
+
const identity = toolIdentity(extracted.server, extracted.name);
|
|
5493
|
+
pendingToolAggregate[identity] = (pendingToolAggregate[identity] ?? 0) + 1;
|
|
5494
|
+
continue;
|
|
5495
|
+
}
|
|
5496
|
+
if (pt && TOOL_CALL_OUTPUT_PAYLOAD_TYPES.has(pt)) {
|
|
5497
|
+
const p = payload;
|
|
5498
|
+
const callId = firstString(p.call_id, p.id);
|
|
5499
|
+
const open2 = callId ? openCalls.get(callId) : void 0;
|
|
5500
|
+
if (!callId || !open2) {
|
|
5501
|
+
skipped += 1;
|
|
5502
|
+
continue;
|
|
5503
|
+
}
|
|
5504
|
+
openCalls.delete(callId);
|
|
5505
|
+
open2.ended_at = r.timestamp ?? lastTs ?? open2.started_at;
|
|
5506
|
+
open2.result_bytes = jsonBytes(p.output ?? p.result);
|
|
5507
|
+
if (open2.status === "unknown") {
|
|
5508
|
+
open2.status = outputIndicatesError(p) ? "error" : "success";
|
|
5509
|
+
}
|
|
5510
|
+
continue;
|
|
5511
|
+
}
|
|
5512
|
+
skipped += 1;
|
|
4997
5513
|
continue;
|
|
4998
5514
|
}
|
|
4999
5515
|
if (obj.type === "event_msg") {
|
|
5000
5516
|
const m = obj;
|
|
5001
5517
|
const ts = m.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
5002
5518
|
const payload = m.payload;
|
|
5003
|
-
if (!payload
|
|
5519
|
+
if (!payload?.type) {
|
|
5004
5520
|
skipped += 1;
|
|
5005
5521
|
continue;
|
|
5006
5522
|
}
|
|
@@ -5037,11 +5553,12 @@ async function parseCodexRollout(ctx) {
|
|
|
5037
5553
|
reasoning: tk.reasoning_output_tokens ?? 0
|
|
5038
5554
|
},
|
|
5039
5555
|
duration_ms: null,
|
|
5040
|
-
tool_calls:
|
|
5556
|
+
tool_calls: pendingToolAggregate,
|
|
5041
5557
|
files_touched: [],
|
|
5042
5558
|
source_file: ctx.sourceFile,
|
|
5043
5559
|
source_byte_offset: offsetAtLineStart
|
|
5044
5560
|
});
|
|
5561
|
+
pendingToolAggregate = {};
|
|
5045
5562
|
turnIndex += 1;
|
|
5046
5563
|
continue;
|
|
5047
5564
|
}
|
|
@@ -5079,16 +5596,39 @@ async function parseCodexRollout(ctx) {
|
|
|
5079
5596
|
if (ctx.onEvents && chunk.length > 0) await ctx.onEvents(chunk);
|
|
5080
5597
|
return {
|
|
5081
5598
|
events,
|
|
5599
|
+
toolCalls,
|
|
5082
5600
|
stats: { rawLines, emittedEvents: emitted, skipped },
|
|
5083
5601
|
sourceFile: ctx.sourceFile
|
|
5084
5602
|
};
|
|
5085
5603
|
}
|
|
5604
|
+
var TOOL_CALL_PAYLOAD_TYPES, TOOL_CALL_OUTPUT_PAYLOAD_TYPES, SHELL_TOOL_NAMES2, SHELL_WRAPPER_BINARIES;
|
|
5086
5605
|
var init_codex = __esm({
|
|
5087
5606
|
"../../packages/parsers/src/codex/index.ts"() {
|
|
5088
5607
|
"use strict";
|
|
5089
5608
|
init_src();
|
|
5090
|
-
init_types();
|
|
5091
5609
|
init_git();
|
|
5610
|
+
init_shell_families();
|
|
5611
|
+
init_tool_hash();
|
|
5612
|
+
init_types();
|
|
5613
|
+
TOOL_CALL_PAYLOAD_TYPES = /* @__PURE__ */ new Set([
|
|
5614
|
+
"function_call",
|
|
5615
|
+
"local_shell_call",
|
|
5616
|
+
"custom_tool_call",
|
|
5617
|
+
"mcp_tool_call"
|
|
5618
|
+
]);
|
|
5619
|
+
TOOL_CALL_OUTPUT_PAYLOAD_TYPES = /* @__PURE__ */ new Set([
|
|
5620
|
+
"function_call_output",
|
|
5621
|
+
"local_shell_call_output",
|
|
5622
|
+
"custom_tool_call_output",
|
|
5623
|
+
"mcp_tool_call_output"
|
|
5624
|
+
]);
|
|
5625
|
+
SHELL_TOOL_NAMES2 = /* @__PURE__ */ new Set([
|
|
5626
|
+
"shell",
|
|
5627
|
+
"local_shell_call",
|
|
5628
|
+
"exec_command",
|
|
5629
|
+
"run_terminal_cmd"
|
|
5630
|
+
]);
|
|
5631
|
+
SHELL_WRAPPER_BINARIES = /* @__PURE__ */ new Set(["bash", "sh", "zsh", "dash", "fish"]);
|
|
5092
5632
|
}
|
|
5093
5633
|
});
|
|
5094
5634
|
|
|
@@ -44392,6 +44932,12 @@ var init_ids2 = __esm({
|
|
|
44392
44932
|
});
|
|
44393
44933
|
|
|
44394
44934
|
// ../../packages/companion-core/src/queue/index.ts
|
|
44935
|
+
function attachSegmentIdsByMap(calls, segmentByEvent) {
|
|
44936
|
+
return calls.map((c) => ({
|
|
44937
|
+
...c,
|
|
44938
|
+
segment_id: segmentByEvent.get(c.source_event_id) ?? null
|
|
44939
|
+
}));
|
|
44940
|
+
}
|
|
44395
44941
|
var init_queue = __esm({
|
|
44396
44942
|
"../../packages/companion-core/src/queue/index.ts"() {
|
|
44397
44943
|
"use strict";
|
|
@@ -44400,21 +44946,6 @@ var init_queue = __esm({
|
|
|
44400
44946
|
}
|
|
44401
44947
|
});
|
|
44402
44948
|
|
|
44403
|
-
// ../../packages/companion-core/src/pipeline/prompts.ts
|
|
44404
|
-
var OLLAMA_CHAT_MODEL, OLLAMA_EMBED_MODEL, SUMMARISER_SYSTEM_PROMPT, SUMMARISER_MAX_TOKENS, SUMMARISER_TEMPERATURE, QWEN_CHARS_PER_TOKEN, ABSTRACT_OUTPUT_MAX_CHARS;
|
|
44405
|
-
var init_prompts = __esm({
|
|
44406
|
-
"../../packages/companion-core/src/pipeline/prompts.ts"() {
|
|
44407
|
-
"use strict";
|
|
44408
|
-
OLLAMA_CHAT_MODEL = "qwen3:4b";
|
|
44409
|
-
OLLAMA_EMBED_MODEL = "bge-small-en-v1.5";
|
|
44410
|
-
SUMMARISER_SYSTEM_PROMPT = "You summarise an AI coding session in ONE sentence, \u2264 240 characters. If the user message includes sampled conversation excerpts, base your summary on what the developer was actually working on (the substance \u2014 what was being built, debugged, refactored, or designed). If only metadata is given, paraphrase the metadata. Never quote the excerpts verbatim. No PII, no code literals, no file paths, no API keys. Reply with only the sentence.";
|
|
44411
|
-
SUMMARISER_MAX_TOKENS = 120;
|
|
44412
|
-
SUMMARISER_TEMPERATURE = 0.2;
|
|
44413
|
-
QWEN_CHARS_PER_TOKEN = 3.3;
|
|
44414
|
-
ABSTRACT_OUTPUT_MAX_CHARS = 240;
|
|
44415
|
-
}
|
|
44416
|
-
});
|
|
44417
|
-
|
|
44418
44949
|
// ../../packages/companion-core/src/pipeline/cognition.ts
|
|
44419
44950
|
function buildCognitionUserPrompt(abstract) {
|
|
44420
44951
|
return `Summary: "${abstract.replace(/\s+/g, " ").trim().slice(0, 480)}"
|
|
@@ -44497,6 +45028,21 @@ var init_cognition = __esm({
|
|
|
44497
45028
|
}
|
|
44498
45029
|
});
|
|
44499
45030
|
|
|
45031
|
+
// ../../packages/companion-core/src/pipeline/prompts.ts
|
|
45032
|
+
var OLLAMA_CHAT_MODEL, OLLAMA_EMBED_MODEL, SUMMARISER_SYSTEM_PROMPT, SUMMARISER_MAX_TOKENS, SUMMARISER_TEMPERATURE, QWEN_CHARS_PER_TOKEN, ABSTRACT_OUTPUT_MAX_CHARS;
|
|
45033
|
+
var init_prompts = __esm({
|
|
45034
|
+
"../../packages/companion-core/src/pipeline/prompts.ts"() {
|
|
45035
|
+
"use strict";
|
|
45036
|
+
OLLAMA_CHAT_MODEL = "qwen3:4b";
|
|
45037
|
+
OLLAMA_EMBED_MODEL = "bge-small-en-v1.5";
|
|
45038
|
+
SUMMARISER_SYSTEM_PROMPT = "You summarise an AI coding session in ONE sentence, \u2264 240 characters. If the user message includes sampled conversation excerpts, base your summary on what the developer was actually working on (the substance \u2014 what was being built, debugged, refactored, or designed). If only metadata is given, paraphrase the metadata. Never quote the excerpts verbatim. No PII, no code literals, no file paths, no API keys. Reply with only the sentence.";
|
|
45039
|
+
SUMMARISER_MAX_TOKENS = 120;
|
|
45040
|
+
SUMMARISER_TEMPERATURE = 0.2;
|
|
45041
|
+
QWEN_CHARS_PER_TOKEN = 3.3;
|
|
45042
|
+
ABSTRACT_OUTPUT_MAX_CHARS = 240;
|
|
45043
|
+
}
|
|
45044
|
+
});
|
|
45045
|
+
|
|
44500
45046
|
// ../../packages/companion-core/src/pipeline/title.ts
|
|
44501
45047
|
function buildTitleUserPrompt(input) {
|
|
44502
45048
|
const lines = input.abstracts.map(
|
|
@@ -44674,9 +45220,7 @@ async function buildForOneSession(sessionId, events, adapters2, onSlice) {
|
|
|
44674
45220
|
} catch (err) {
|
|
44675
45221
|
failed += 1;
|
|
44676
45222
|
lastError = err instanceof Error ? err.message : String(err);
|
|
44677
|
-
console.warn(
|
|
44678
|
-
`[modelstat] slice failed in session ${sessionId}: ${lastError}`
|
|
44679
|
-
);
|
|
45223
|
+
console.warn(`[modelstat] slice failed in session ${sessionId}: ${lastError}`);
|
|
44680
45224
|
}
|
|
44681
45225
|
}
|
|
44682
45226
|
if (failed > 0) {
|
|
@@ -44781,6 +45325,24 @@ Write the SHORTEST keyword-dense paragraph (1-3 sentences, \u2264${ABSTRACT_OUTP
|
|
|
44781
45325
|
for (const c of [...components].slice(0, 8)) {
|
|
44782
45326
|
tags.push({ root_key: "components", name: c, confidence: 0.6 });
|
|
44783
45327
|
}
|
|
45328
|
+
const toolCallCounts = /* @__PURE__ */ new Map();
|
|
45329
|
+
let toolCallTotal = 0;
|
|
45330
|
+
for (const ev of slice) {
|
|
45331
|
+
for (const [identity, n] of Object.entries(ev.tool_calls ?? {})) {
|
|
45332
|
+
if (!(n > 0)) continue;
|
|
45333
|
+
toolCallCounts.set(identity, (toolCallCounts.get(identity) ?? 0) + n);
|
|
45334
|
+
toolCallTotal += n;
|
|
45335
|
+
}
|
|
45336
|
+
}
|
|
45337
|
+
const topToolCalls = [...toolCallCounts.entries()].filter(([identity]) => identity.length <= 120).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, 8);
|
|
45338
|
+
for (const [identity, count] of topToolCalls) {
|
|
45339
|
+
const share = Math.round(count / toolCallTotal * 100) / 100;
|
|
45340
|
+
tags.push({
|
|
45341
|
+
root_key: "tool_calls",
|
|
45342
|
+
name: identity,
|
|
45343
|
+
confidence: Math.min(1, Math.max(0.05, share))
|
|
45344
|
+
});
|
|
45345
|
+
}
|
|
44784
45346
|
let segmentEmbedding;
|
|
44785
45347
|
try {
|
|
44786
45348
|
const embedded = await adapters2.embed(redacted.text.slice(0, ABSTRACT_MAX_CHARS));
|
|
@@ -44868,13 +45430,13 @@ var SEGMENT_TIME_GAP_MS, SEGMENT_TOPIC_THRESHOLD, SEGMENT_MAX_TURNS, SEGMENT_MAX
|
|
|
44868
45430
|
var init_pipeline = __esm({
|
|
44869
45431
|
"../../packages/companion-core/src/pipeline/index.ts"() {
|
|
44870
45432
|
"use strict";
|
|
44871
|
-
init_redact();
|
|
44872
45433
|
init_ids();
|
|
44873
|
-
init_prompts();
|
|
44874
|
-
init_cognition();
|
|
44875
45434
|
init_redact();
|
|
45435
|
+
init_cognition();
|
|
44876
45436
|
init_prompts();
|
|
45437
|
+
init_redact();
|
|
44877
45438
|
init_cognition();
|
|
45439
|
+
init_prompts();
|
|
44878
45440
|
init_title();
|
|
44879
45441
|
SEGMENT_TIME_GAP_MS = 15 * 6e4;
|
|
44880
45442
|
SEGMENT_TOPIC_THRESHOLD = 0.35;
|
|
@@ -45698,7 +46260,8 @@ async function scanAll(cb = {}) {
|
|
|
45698
46260
|
jobs.push({
|
|
45699
46261
|
path: full,
|
|
45700
46262
|
parse: async (sink2) => {
|
|
45701
|
-
await parseClaudeCodeJsonl({ deviceId, sourceFile: full, onEvents: sink2 });
|
|
46263
|
+
const r = await parseClaudeCodeJsonl({ deviceId, sourceFile: full, onEvents: sink2 });
|
|
46264
|
+
return { toolCalls: r.toolCalls ?? [] };
|
|
45702
46265
|
}
|
|
45703
46266
|
});
|
|
45704
46267
|
}
|
|
@@ -45721,7 +46284,8 @@ async function scanAll(cb = {}) {
|
|
|
45721
46284
|
jobs.push({
|
|
45722
46285
|
path: full,
|
|
45723
46286
|
parse: async (sink2) => {
|
|
45724
|
-
await parseCodexRollout({ deviceId, sourceFile: full, onEvents: sink2 });
|
|
46287
|
+
const r = await parseCodexRollout({ deviceId, sourceFile: full, onEvents: sink2 });
|
|
46288
|
+
return { toolCalls: r.toolCalls ?? [] };
|
|
45725
46289
|
}
|
|
45726
46290
|
});
|
|
45727
46291
|
}
|
|
@@ -45737,10 +46301,11 @@ async function scanAll(cb = {}) {
|
|
|
45737
46301
|
let eventsUploaded = 0;
|
|
45738
46302
|
let segmentsUploaded = 0;
|
|
45739
46303
|
let buffer = [];
|
|
46304
|
+
let toolCallBuffer = [];
|
|
45740
46305
|
let pendingCursors = [];
|
|
45741
46306
|
const runSegmentsBySession = /* @__PURE__ */ new Map();
|
|
45742
46307
|
async function flushBatch() {
|
|
45743
|
-
if (!buffer.length) return;
|
|
46308
|
+
if (!buffer.length && !toolCallBuffer.length) return;
|
|
45744
46309
|
const events = buffer.map(withNonNullTokens);
|
|
45745
46310
|
const segments = await buildSegments(events, cb.onProgress);
|
|
45746
46311
|
for (const seg of segments) {
|
|
@@ -45758,12 +46323,19 @@ async function scanAll(cb = {}) {
|
|
|
45758
46323
|
} catch (e) {
|
|
45759
46324
|
console.warn("session titling failed \u2014 shipping batch untitled:", e.message);
|
|
45760
46325
|
}
|
|
46326
|
+
const callSegmentByEvent = /* @__PURE__ */ new Map();
|
|
46327
|
+
for (const sessionId of new Set(toolCallBuffer.map((c) => c.session_id))) {
|
|
46328
|
+
for (const seg of runSegmentsBySession.get(sessionId) ?? []) {
|
|
46329
|
+
for (const id of seg.source_event_ids) callSegmentByEvent.set(id, seg.segment_id);
|
|
46330
|
+
}
|
|
46331
|
+
}
|
|
45761
46332
|
const batch = {
|
|
45762
46333
|
batch_id: batchId(),
|
|
45763
46334
|
device_id: deviceId,
|
|
45764
46335
|
agent_version: AGENT_VERSION,
|
|
45765
46336
|
events,
|
|
45766
46337
|
segments,
|
|
46338
|
+
tool_calls: attachSegmentIdsByMap(toolCallBuffer, callSegmentByEvent),
|
|
45767
46339
|
...Object.keys(sessionTitles).length ? { session_titles: sessionTitles } : {}
|
|
45768
46340
|
};
|
|
45769
46341
|
cb.onUpload?.({ events: events.length, segments: segments.length });
|
|
@@ -45774,6 +46346,7 @@ async function scanAll(cb = {}) {
|
|
|
45774
46346
|
for (const pc of pendingCursors) state.setCursor(pc.path, pc.cs);
|
|
45775
46347
|
pendingCursors = [];
|
|
45776
46348
|
buffer = [];
|
|
46349
|
+
toolCallBuffer = [];
|
|
45777
46350
|
cb.onUploaded?.({ events: res.accepted, segments: segments.length });
|
|
45778
46351
|
}
|
|
45779
46352
|
const sink = async (events) => {
|
|
@@ -45787,6 +46360,12 @@ async function scanAll(cb = {}) {
|
|
|
45787
46360
|
);
|
|
45788
46361
|
}
|
|
45789
46362
|
};
|
|
46363
|
+
const bufferToolCalls = async (calls) => {
|
|
46364
|
+
for (const c of calls) {
|
|
46365
|
+
if (toolCallBuffer.length >= BATCH_MAX_TOOL_CALLS) await flushBatch();
|
|
46366
|
+
toolCallBuffer.push(c);
|
|
46367
|
+
}
|
|
46368
|
+
};
|
|
45790
46369
|
for (let i = 0; i < jobs.length; i++) {
|
|
45791
46370
|
const job = jobs[i];
|
|
45792
46371
|
cb.onFile?.(job.path, i, jobs.length);
|
|
@@ -45798,7 +46377,8 @@ async function scanAll(cb = {}) {
|
|
|
45798
46377
|
}
|
|
45799
46378
|
filesScanned += 1;
|
|
45800
46379
|
try {
|
|
45801
|
-
await job.parse(sink);
|
|
46380
|
+
const r = await job.parse(sink);
|
|
46381
|
+
await bufferToolCalls(r.toolCalls);
|
|
45802
46382
|
if (cs) pendingCursors.push({ path: job.path, cs });
|
|
45803
46383
|
} catch (e) {
|
|
45804
46384
|
console.warn(` ! parse failed for ${job.path}:`, e.message);
|
|
@@ -45807,17 +46387,19 @@ async function scanAll(cb = {}) {
|
|
|
45807
46387
|
await flushBatch();
|
|
45808
46388
|
return { filesScanned, filesUnchanged, batchesUploaded, eventsUploaded, segmentsUploaded };
|
|
45809
46389
|
}
|
|
45810
|
-
var AGENT_VERSION, BATCH_MAX_EVENTS, BATCH_BUFFER_HARD_CAP, ZERO_TOKENS;
|
|
46390
|
+
var AGENT_VERSION, BATCH_MAX_EVENTS, BATCH_MAX_TOOL_CALLS, BATCH_BUFFER_HARD_CAP, ZERO_TOKENS;
|
|
45811
46391
|
var init_scan = __esm({
|
|
45812
46392
|
"src/scan.ts"() {
|
|
45813
46393
|
"use strict";
|
|
45814
|
-
init_src2();
|
|
45815
46394
|
init_src3();
|
|
45816
|
-
|
|
45817
|
-
|
|
46395
|
+
init_queue();
|
|
46396
|
+
init_src2();
|
|
45818
46397
|
init_api();
|
|
45819
|
-
|
|
46398
|
+
init_config2();
|
|
46399
|
+
init_pipeline2();
|
|
46400
|
+
AGENT_VERSION = true ? "agent-0.0.48" : "agent-dev";
|
|
45820
46401
|
BATCH_MAX_EVENTS = 2e3;
|
|
46402
|
+
BATCH_MAX_TOOL_CALLS = 2e4;
|
|
45821
46403
|
BATCH_BUFFER_HARD_CAP = BATCH_MAX_EVENTS * 2;
|
|
45822
46404
|
ZERO_TOKENS = {
|
|
45823
46405
|
input: 0,
|
|
@@ -46028,7 +46610,7 @@ var PROCESSING_VERSION;
|
|
|
46028
46610
|
var init_processing_version = __esm({
|
|
46029
46611
|
"src/processing-version.ts"() {
|
|
46030
46612
|
"use strict";
|
|
46031
|
-
PROCESSING_VERSION =
|
|
46613
|
+
PROCESSING_VERSION = 5;
|
|
46032
46614
|
}
|
|
46033
46615
|
});
|
|
46034
46616
|
|
|
@@ -48075,7 +48657,7 @@ var init_daemon = __esm({
|
|
|
48075
48657
|
init_lock();
|
|
48076
48658
|
init_scan();
|
|
48077
48659
|
init_single_flight();
|
|
48078
|
-
AGENT_VERSION2 = true ? "agent-0.0.
|
|
48660
|
+
AGENT_VERSION2 = true ? "agent-0.0.48" : "agent-dev";
|
|
48079
48661
|
HEARTBEAT_INTERVAL_MS = 1e4;
|
|
48080
48662
|
SCAN_INTERVAL_MS = 5 * 60 * 1e3;
|
|
48081
48663
|
DISCOVERY_INTERVAL_MS = 6e4;
|
|
@@ -48640,7 +49222,7 @@ function tryOpenBrowser(url) {
|
|
|
48640
49222
|
return false;
|
|
48641
49223
|
}
|
|
48642
49224
|
}
|
|
48643
|
-
var AGENT_VERSION3 = true ? "agent-0.0.
|
|
49225
|
+
var AGENT_VERSION3 = true ? "agent-0.0.48" : "agent-dev";
|
|
48644
49226
|
function osFamily() {
|
|
48645
49227
|
const p = platform4();
|
|
48646
49228
|
if (p === "darwin") return "macos";
|